| @@ -1,4 +1,4 @@ | |||
| allprojects { | |||
| allprojects { | |||
| apply plugin: 'maven' | |||
| group = 'com.github.binarywang' | |||
| @@ -19,15 +19,15 @@ subprojects { | |||
| dependencies { | |||
| compile group: 'org.slf4j', name: 'slf4j-api', version:'1.7.10' | |||
| compile group: 'org.apache.httpcomponents', name: 'httpmime', version:'4.5' | |||
| compile group: 'org.apache.httpcomponents', name: 'httpclient', version:'4.5' | |||
| compile group: 'com.google.code.gson', name: 'gson', version:'2.7' | |||
| compile group: 'com.google.guava', name: 'guava', version:'19.0' | |||
| compile group: 'commons-codec', name: 'commons-codec', version:'1.10' | |||
| compile group: 'commons-io', name: 'commons-io', version:'2.5' | |||
| compile group: 'org.apache.commons', name: 'commons-lang3', version:'3.4' | |||
| compile group: 'redis.clients', name: 'jedis', version:'2.9.0' | |||
| testCompile group: 'ch.qos.logback', name: 'logback-classic', version:'1.1.2' | |||
| compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.10' | |||
| compile group: 'org.apache.httpcomponents', name: 'httpmime', version: '4.5' | |||
| compile group: 'org.apache.httpcomponents', name: 'httpclient', version: '4.5' | |||
| compile group: 'com.google.code.gson', name: 'gson', version: '2.7' | |||
| compile group: 'com.google.guava', name: 'guava', version: '19.0' | |||
| compile group: 'commons-codec', name: 'commons-codec', version: '1.10' | |||
| compile group: 'commons-io', name: 'commons-io', version: '2.5' | |||
| compile group: 'org.apache.commons', name: 'commons-lang3', version: '3.4' | |||
| compile group: 'redis.clients', name: 'jedis', version: '2.9.0' | |||
| testCompile group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.2' | |||
| } | |||
| } | |||
| @@ -1,7 +1,8 @@ | |||
| <?xml version="1.0"?> | |||
| <project | |||
| 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"> | |||
| 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"> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <groupId>com.github.binarywang</groupId> | |||
| <artifactId>weixin-java-parent</artifactId> | |||
| @@ -1,12 +1,11 @@ | |||
| description = 'WeiXin Java Tools - Common' | |||
| dependencies { | |||
| compile group: 'com.thoughtworks.xstream', name: 'xstream', version:'1.4.7' | |||
| testCompile group: 'junit', name: 'junit', version:'4.11' | |||
| testCompile group: 'org.testng', name: 'testng', version:'6.8.7' | |||
| testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5' | |||
| testCompile group: 'com.google.inject', name: 'guice', version:'3.0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0' | |||
| compile group: 'com.thoughtworks.xstream', name: 'xstream', version: '1.4.7' | |||
| testCompile group: 'junit', name: 'junit', version: '4.11' | |||
| testCompile group: 'org.testng', name: 'testng', version: '6.8.7' | |||
| testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' | |||
| testCompile group: 'com.google.inject', name: 'guice', version: '3.0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.0.RC0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.3.0.RC0' | |||
| } | |||
| test.useTestNG() | |||
| @@ -1,7 +1,7 @@ | |||
| <?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"> | |||
| 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"> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <parent> | |||
| <groupId>com.github.binarywang</groupId> | |||
| @@ -7,13 +7,13 @@ import java.lang.annotation.Target; | |||
| /** | |||
| * 标识某个字段是否是必填的 | |||
| * | |||
| * <p> | |||
| * Created by Binary Wang on 2016/9/25. | |||
| * @author binarywang (https://github.com/binarywang) | |||
| * | |||
| * @author binarywang (https://github.com/binarywang) | |||
| */ | |||
| @Retention(RetentionPolicy.RUNTIME) | |||
| @Target(ElementType.FIELD) | |||
| public @interface Required { | |||
| } | |||
| } | |||
| @@ -51,7 +51,7 @@ public class WxMediaUploadResult implements Serializable { | |||
| @Override | |||
| public String toString() { | |||
| return "WxUploadResult [type=" + this.type + ", media_id=" + this.mediaId + ", thumb_media_id=" + this.thumbMediaId | |||
| + ", created_at=" + this.createdAt + "]"; | |||
| + ", created_at=" + this.createdAt + "]"; | |||
| } | |||
| } | |||
| @@ -14,7 +14,7 @@ import java.util.concurrent.atomic.AtomicBoolean; | |||
| public class StandardSessionManager implements WxSessionManager, InternalSessionManager { | |||
| protected static final StringManager sm = | |||
| StringManager.getManager(Constants.Package); | |||
| StringManager.getManager(Constants.Package); | |||
| /** | |||
| * The descriptive name of this Manager implementation (for logging). | |||
| */ | |||
| @@ -82,7 +82,7 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||
| public WxSession getSession(String sessionId, boolean create) { | |||
| if (sessionId == null) { | |||
| throw new IllegalStateException | |||
| (sm.getString("sessionManagerImpl.getSession.ise")); | |||
| (sm.getString("sessionManagerImpl.getSession.ise")); | |||
| } | |||
| InternalSession session = findSession(sessionId); | |||
| @@ -135,15 +135,15 @@ public class StandardSessionManager implements WxSessionManager, InternalSession | |||
| public InternalSession createSession(String sessionId) { | |||
| if (sessionId == null) { | |||
| throw new IllegalStateException | |||
| (sm.getString("sessionManagerImpl.createSession.ise")); | |||
| (sm.getString("sessionManagerImpl.createSession.ise")); | |||
| } | |||
| if ((this.maxActiveSessions >= 0) && | |||
| (getActiveSessions() >= this.maxActiveSessions)) { | |||
| (getActiveSessions() >= this.maxActiveSessions)) { | |||
| this.rejectedSessions++; | |||
| throw new TooManyActiveSessionsException( | |||
| sm.getString("sessionManagerImpl.createSession.tmase"), | |||
| this.maxActiveSessions); | |||
| sm.getString("sessionManagerImpl.createSession.tmase"), | |||
| this.maxActiveSessions); | |||
| } | |||
| // Recycle or create a Session instance | |||
| @@ -21,7 +21,7 @@ package me.chanjar.weixin.common.session; | |||
| * reached and the server is refusing to create any new sessions. | |||
| */ | |||
| public class TooManyActiveSessionsException | |||
| extends IllegalStateException { | |||
| extends IllegalStateException { | |||
| private static final long serialVersionUID = 1L; | |||
| /** | |||
| @@ -13,25 +13,10 @@ import org.apache.commons.lang3.builder.ToStringStyle; | |||
| */ | |||
| public class ToStringUtils { | |||
| public static final ToStringStyle THE_STYLE = new SimpleMultiLineToStringStyle(); | |||
| private static class SimpleMultiLineToStringStyle extends ToStringStyle { | |||
| private static final long serialVersionUID = 4645306494220335355L; | |||
| private static final String LINE_SEPARATOR = "\n"; | |||
| private static final String NULL_TEXT = "<null>"; | |||
| public SimpleMultiLineToStringStyle() { | |||
| super(); | |||
| this.setContentStart("["); | |||
| this.setFieldSeparator(LINE_SEPARATOR + " "); | |||
| this.setFieldSeparatorAtStart(true); | |||
| this.setContentEnd(LINE_SEPARATOR + "]"); | |||
| this.setNullText(NULL_TEXT); | |||
| this.setUseShortClassName(true); | |||
| this.setUseIdentityHashCode(false); | |||
| } | |||
| } | |||
| /** | |||
| * 用于产生去掉空值属性并以换行符分割各属性键值的toString字符串 | |||
| * | |||
| * @param obj | |||
| */ | |||
| public static String toSimpleString(Object obj) { | |||
| @@ -58,4 +43,21 @@ public class ToStringUtils { | |||
| return result.deleteCharAt(result.length() - 1).toString(); | |||
| } | |||
| private static class SimpleMultiLineToStringStyle extends ToStringStyle { | |||
| private static final long serialVersionUID = 4645306494220335355L; | |||
| private static final String LINE_SEPARATOR = "\n"; | |||
| private static final String NULL_TEXT = "<null>"; | |||
| public SimpleMultiLineToStringStyle() { | |||
| super(); | |||
| this.setContentStart("["); | |||
| this.setFieldSeparator(LINE_SEPARATOR + " "); | |||
| this.setFieldSeparatorAtStart(true); | |||
| this.setContentEnd(LINE_SEPARATOR + "]"); | |||
| this.setNullText(NULL_TEXT); | |||
| this.setUseShortClassName(true); | |||
| this.setUseIdentityHashCode(false); | |||
| } | |||
| } | |||
| } | |||
| @@ -1,9 +1,9 @@ | |||
| package me.chanjar.weixin.common.util.crypto; | |||
| import java.util.Arrays; | |||
| import org.apache.commons.codec.digest.DigestUtils; | |||
| import java.util.Arrays; | |||
| /** | |||
| * Created by Daniel Qian on 14/10/19. | |||
| */ | |||
| @@ -6,6 +6,10 @@ | |||
| * 针对org.apache.commons.codec.binary.Base64, | |||
| * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | |||
| * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | |||
| * <p> | |||
| * 针对org.apache.commons.codec.binary.Base64, | |||
| * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | |||
| * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | |||
| */ | |||
| // ------------------------------------------------------------------------ | |||
| @@ -17,10 +21,10 @@ | |||
| */ | |||
| package me.chanjar.weixin.common.util.crypto; | |||
| import java.io.StringReader; | |||
| import java.nio.charset.Charset; | |||
| import java.util.Arrays; | |||
| import java.util.Random; | |||
| import org.apache.commons.codec.binary.Base64; | |||
| import org.w3c.dom.Document; | |||
| import org.w3c.dom.Element; | |||
| import org.xml.sax.InputSource; | |||
| import javax.crypto.Cipher; | |||
| import javax.crypto.spec.IvParameterSpec; | |||
| @@ -28,11 +32,10 @@ import javax.crypto.spec.SecretKeySpec; | |||
| import javax.xml.parsers.DocumentBuilder; | |||
| import javax.xml.parsers.DocumentBuilderFactory; | |||
| import javax.xml.parsers.ParserConfigurationException; | |||
| import org.apache.commons.codec.binary.Base64; | |||
| import org.w3c.dom.Document; | |||
| import org.w3c.dom.Element; | |||
| import org.xml.sax.InputSource; | |||
| import java.io.StringReader; | |||
| import java.nio.charset.Charset; | |||
| import java.util.Arrays; | |||
| import java.util.Random; | |||
| public class WxCryptUtil { | |||
| @@ -84,6 +87,66 @@ public class WxCryptUtil { | |||
| } | |||
| } | |||
| /** | |||
| * 将一个数字转换成生成4个字节的网络字节序bytes数组 | |||
| * | |||
| * @param number | |||
| */ | |||
| private static byte[] number2BytesInNetworkOrder(int number) { | |||
| byte[] orderBytes = new byte[4]; | |||
| orderBytes[3] = (byte) (number & 0xFF); | |||
| orderBytes[2] = (byte) (number >> 8 & 0xFF); | |||
| orderBytes[1] = (byte) (number >> 16 & 0xFF); | |||
| orderBytes[0] = (byte) (number >> 24 & 0xFF); | |||
| return orderBytes; | |||
| } | |||
| /** | |||
| * 4个字节的网络字节序bytes数组还原成一个数字 | |||
| * | |||
| * @param bytesInNetworkOrder | |||
| */ | |||
| private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { | |||
| int sourceNumber = 0; | |||
| for (int i = 0; i < 4; i++) { | |||
| sourceNumber <<= 8; | |||
| sourceNumber |= bytesInNetworkOrder[i] & 0xff; | |||
| } | |||
| return sourceNumber; | |||
| } | |||
| /** | |||
| * 随机生成16位字符串 | |||
| */ | |||
| private static String genRandomStr() { | |||
| String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |||
| Random random = new Random(); | |||
| StringBuffer sb = new StringBuffer(); | |||
| for (int i = 0; i < 16; i++) { | |||
| int number = random.nextInt(base.length()); | |||
| sb.append(base.charAt(number)); | |||
| } | |||
| return sb.toString(); | |||
| } | |||
| /** | |||
| * 生成xml消息 | |||
| * | |||
| * @param encrypt 加密后的消息密文 | |||
| * @param signature 安全签名 | |||
| * @param timestamp 时间戳 | |||
| * @param nonce 随机字符串 | |||
| * @return 生成的xml字符串 | |||
| */ | |||
| private static 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); | |||
| } | |||
| /** | |||
| * 将公众平台回复用户的消息加密打包. | |||
| * <ol> | |||
| @@ -119,7 +182,7 @@ public class WxCryptUtil { | |||
| byte[] randomStringBytes = randomStr.getBytes(CHARSET); | |||
| byte[] plainTextBytes = plainText.getBytes(CHARSET); | |||
| byte[] bytesOfSizeInNetworkOrder = number2BytesInNetworkOrder( | |||
| plainTextBytes.length); | |||
| plainTextBytes.length); | |||
| byte[] appIdBytes = this.appidOrCorpid.getBytes(CHARSET); | |||
| // randomStr + networkBytesOrder + text + appid | |||
| @@ -198,7 +261,7 @@ public class WxCryptUtil { | |||
| Cipher cipher = Cipher.getInstance("AES/CBC/NoPadding"); | |||
| SecretKeySpec key_spec = new SecretKeySpec(this.aesKey, "AES"); | |||
| IvParameterSpec iv = new IvParameterSpec( | |||
| Arrays.copyOfRange(this.aesKey, 0, 16)); | |||
| Arrays.copyOfRange(this.aesKey, 0, 16)); | |||
| cipher.init(Cipher.DECRYPT_MODE, key_spec, iv); | |||
| // 使用BASE64对密文进行解码 | |||
| @@ -221,9 +284,9 @@ public class WxCryptUtil { | |||
| int xmlLength = bytesNetworkOrder2Number(networkOrder); | |||
| xmlContent = new String(Arrays.copyOfRange(bytes, 20, 20 + xmlLength), | |||
| CHARSET); | |||
| CHARSET); | |||
| from_appid = new String( | |||
| Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | |||
| Arrays.copyOfRange(bytes, 20 + xmlLength, bytes.length), CHARSET); | |||
| } catch (Exception e) { | |||
| throw new RuntimeException(e); | |||
| } | |||
| @@ -237,64 +300,4 @@ public class WxCryptUtil { | |||
| } | |||
| /** | |||
| * 将一个数字转换成生成4个字节的网络字节序bytes数组 | |||
| * | |||
| * @param number | |||
| */ | |||
| private static byte[] number2BytesInNetworkOrder(int number) { | |||
| byte[] orderBytes = new byte[4]; | |||
| orderBytes[3] = (byte) (number & 0xFF); | |||
| orderBytes[2] = (byte) (number >> 8 & 0xFF); | |||
| orderBytes[1] = (byte) (number >> 16 & 0xFF); | |||
| orderBytes[0] = (byte) (number >> 24 & 0xFF); | |||
| return orderBytes; | |||
| } | |||
| /** | |||
| * 4个字节的网络字节序bytes数组还原成一个数字 | |||
| * | |||
| * @param bytesInNetworkOrder | |||
| */ | |||
| private static int bytesNetworkOrder2Number(byte[] bytesInNetworkOrder) { | |||
| int sourceNumber = 0; | |||
| for (int i = 0; i < 4; i++) { | |||
| sourceNumber <<= 8; | |||
| sourceNumber |= bytesInNetworkOrder[i] & 0xff; | |||
| } | |||
| return sourceNumber; | |||
| } | |||
| /** | |||
| * 随机生成16位字符串 | |||
| */ | |||
| private static String genRandomStr() { | |||
| String base = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; | |||
| Random random = new Random(); | |||
| StringBuffer sb = new StringBuffer(); | |||
| for (int i = 0; i < 16; i++) { | |||
| int number = random.nextInt(base.length()); | |||
| sb.append(base.charAt(number)); | |||
| } | |||
| return sb.toString(); | |||
| } | |||
| /** | |||
| * 生成xml消息 | |||
| * | |||
| * @param encrypt 加密后的消息密文 | |||
| * @param signature 安全签名 | |||
| * @param timestamp 时间戳 | |||
| * @param nonce 随机字符串 | |||
| * @return 生成的xml字符串 | |||
| */ | |||
| private static 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); | |||
| } | |||
| } | |||
| @@ -25,7 +25,7 @@ public class FileUtils { | |||
| } | |||
| tmpFile.deleteOnExit(); | |||
| try (FileOutputStream fos = new FileOutputStream(tmpFile)) { | |||
| int read = 0; | |||
| byte[] bytes = new byte[1024 * 100]; | |||
| @@ -35,7 +35,7 @@ public class FileUtils { | |||
| fos.flush(); | |||
| return tmpFile; | |||
| } | |||
| } | |||
| } | |||
| /** | |||
| @@ -1,38 +1,10 @@ | |||
| package me.chanjar.weixin.common.util.http; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| import jodd.http.ProxyInfo; | |||
| 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.apache.ApacheMediaDownloadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.apache.InputStreamResponseHandler; | |||
| import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; | |||
| import me.chanjar.weixin.common.util.http.jodd.JoddMediaDownloadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkMediaDownloadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; | |||
| import okhttp3.*; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.apache.http.Header; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.client.config.RequestConfig; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.client.methods.HttpGet; | |||
| import org.apache.http.entity.ContentType; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.net.InetSocketAddress; | |||
| import java.net.Proxy; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| /** | |||
| * 下载媒体文件请求执行器,请求的参数是String, 返回的结果是File | |||
| @@ -42,8 +14,14 @@ import java.util.regex.Pattern; | |||
| */ | |||
| public abstract class MediaDownloadRequestExecutor<H, P> implements RequestExecutor<File, String> { | |||
| public static RequestExecutor<File, String> create(RequestHttp requestHttp, File tmpDirFile){ | |||
| switch (requestHttp.getRequestType()){ | |||
| protected RequestHttp<H, P> requestHttp; | |||
| protected File tmpDirFile; | |||
| public MediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { | |||
| this.tmpDirFile = tmpDirFile; | |||
| } | |||
| public static RequestExecutor<File, String> create(RequestHttp requestHttp, File tmpDirFile) { | |||
| switch (requestHttp.getRequestType()) { | |||
| case apacheHttp: | |||
| return new ApacheMediaDownloadRequestExecutor(requestHttp, tmpDirFile); | |||
| case joddHttp: | |||
| @@ -55,11 +33,4 @@ public abstract class MediaDownloadRequestExecutor<H, P> implements RequestExecu | |||
| } | |||
| } | |||
| protected RequestHttp<H, P> requestHttp; | |||
| protected File tmpDirFile; | |||
| public MediaDownloadRequestExecutor(RequestHttp requestHttp, File tmpDirFile) { | |||
| this.tmpDirFile = tmpDirFile; | |||
| } | |||
| } | |||
| @@ -1,34 +1,11 @@ | |||
| package me.chanjar.weixin.common.util.http; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| import jodd.http.ProxyInfo; | |||
| 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.http.apache.ApacheMediaUploadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; | |||
| import me.chanjar.weixin.common.util.http.jodd.JoddMediaUploadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkMediaUploadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; | |||
| import okhttp3.*; | |||
| import org.apache.http.HttpEntity; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.client.config.RequestConfig; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.client.methods.HttpPost; | |||
| import org.apache.http.entity.ContentType; | |||
| import org.apache.http.entity.mime.HttpMultipartMode; | |||
| import org.apache.http.entity.mime.MultipartEntityBuilder; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.net.InetSocketAddress; | |||
| import java.net.Proxy; | |||
| /** | |||
| * 上传媒体文件请求执行器,请求的参数是File, 返回的结果是String | |||
| @@ -36,14 +13,14 @@ import java.net.Proxy; | |||
| * @author Daniel Qian | |||
| */ | |||
| public abstract class MediaUploadRequestExecutor<H, P> implements RequestExecutor<WxMediaUploadResult, File> { | |||
| protected RequestHttp<H,P> requestHttp; | |||
| protected RequestHttp<H, P> requestHttp; | |||
| public MediaUploadRequestExecutor(RequestHttp requestHttp){ | |||
| this.requestHttp =requestHttp; | |||
| public MediaUploadRequestExecutor(RequestHttp requestHttp) { | |||
| this.requestHttp = requestHttp; | |||
| } | |||
| public static RequestExecutor<WxMediaUploadResult, File> create(RequestHttp requestHttp){ | |||
| switch (requestHttp.getRequestType()){ | |||
| public static RequestExecutor<WxMediaUploadResult, File> create(RequestHttp requestHttp) { | |||
| switch (requestHttp.getRequestType()) { | |||
| case apacheHttp: | |||
| return new ApacheMediaUploadRequestExecutor(requestHttp); | |||
| case joddHttp: | |||
| @@ -1,17 +1,9 @@ | |||
| package me.chanjar.weixin.common.util.http; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.ProxyInfo; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; | |||
| import okhttp3.ConnectionPool; | |||
| import java.io.IOException; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| /** | |||
| * http请求执行器 | |||
| * | |||
| @@ -41,15 +33,15 @@ public interface RequestExecutor<T, E> { | |||
| T executeApache(CloseableHttpClient httpclient, HttpHost httpProxy, String uri, E data) throws WxErrorException, IOException; | |||
| *//** | |||
| * jodd-http实现方式 | |||
| * @param provider | |||
| * @param proxyInfo | |||
| * @param uri | |||
| * @param data | |||
| * @return | |||
| * @throws WxErrorException | |||
| * @throws IOException | |||
| *//* | |||
| * jodd-http实现方式 | |||
| * @param provider | |||
| * @param proxyInfo | |||
| * @param uri | |||
| * @param data | |||
| * @return | |||
| * @throws WxErrorException | |||
| * @throws IOException | |||
| *//* | |||
| T executeJodd(HttpConnectionProvider provider, ProxyInfo proxyInfo, String uri, E data) throws WxErrorException, IOException; | |||
| @@ -3,22 +3,23 @@ package me.chanjar.weixin.common.util.http; | |||
| /** | |||
| * Created by ecoolper on 2017/4/22. | |||
| */ | |||
| public interface RequestHttp<H,P> { | |||
| public interface RequestHttp<H, P> { | |||
| /** | |||
| * 返回httpClient | |||
| * | |||
| * @return | |||
| */ | |||
| H getRequestHttpClient(); | |||
| /** | |||
| * 返回httpProxy | |||
| * | |||
| * @return | |||
| */ | |||
| P getRequestHttpProxy(); | |||
| /** | |||
| * | |||
| * @return | |||
| */ | |||
| HttpType getRequestType(); | |||
| @@ -1,29 +1,8 @@ | |||
| package me.chanjar.weixin.common.util.http; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| import jodd.http.ProxyInfo; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.apache.ApacheSimpleGetRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; | |||
| import me.chanjar.weixin.common.util.http.jodd.JoddSimpleGetRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkSimpleGetRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; | |||
| import okhttp3.*; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.client.config.RequestConfig; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.client.methods.HttpGet; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import java.io.IOException; | |||
| import java.net.InetSocketAddress; | |||
| import java.net.Proxy; | |||
| import java.util.concurrent.TimeUnit; | |||
| /** | |||
| * 简单的GET请求执行器,请求的参数是String, 返回的结果也是String | |||
| @@ -31,15 +10,15 @@ import java.util.concurrent.TimeUnit; | |||
| * @author Daniel Qian | |||
| */ | |||
| public abstract class SimpleGetRequestExecutor<H, P> implements RequestExecutor<String, String> { | |||
| protected RequestHttp<H,P> requestHttp; | |||
| protected RequestHttp<H, P> requestHttp; | |||
| public SimpleGetRequestExecutor(RequestHttp requestHttp){ | |||
| this.requestHttp =requestHttp; | |||
| public SimpleGetRequestExecutor(RequestHttp requestHttp) { | |||
| this.requestHttp = requestHttp; | |||
| } | |||
| public static RequestExecutor<String, String> create(RequestHttp requestHttp){ | |||
| switch(requestHttp.getRequestType()){ | |||
| public static RequestExecutor<String, String> create(RequestHttp requestHttp) { | |||
| switch (requestHttp.getRequestType()) { | |||
| case apacheHttp: | |||
| return new ApacheSimpleGetRequestExecutor(requestHttp); | |||
| case joddHttp: | |||
| @@ -1,29 +1,8 @@ | |||
| package me.chanjar.weixin.common.util.http; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| import jodd.http.ProxyInfo; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.apache.ApacheSimpleGetRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.apache.ApacheSimplePostRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; | |||
| import me.chanjar.weixin.common.util.http.jodd.JoddSimplePostRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkSimplePostRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.okhttp.OkhttpProxyInfo; | |||
| import okhttp3.*; | |||
| import org.apache.http.Consts; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.client.config.RequestConfig; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.client.methods.HttpPost; | |||
| import org.apache.http.entity.StringEntity; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import java.io.IOException; | |||
| /** | |||
| * 用装饰模式实现 | |||
| @@ -32,14 +11,14 @@ import java.io.IOException; | |||
| * @author Daniel Qian | |||
| */ | |||
| public abstract class SimplePostRequestExecutor<H, P> implements RequestExecutor<String, String> { | |||
| protected RequestHttp<H,P> requestHttp; | |||
| protected RequestHttp<H, P> requestHttp; | |||
| public SimplePostRequestExecutor(RequestHttp requestHttp){ | |||
| this.requestHttp =requestHttp; | |||
| public SimplePostRequestExecutor(RequestHttp requestHttp) { | |||
| this.requestHttp = requestHttp; | |||
| } | |||
| public static RequestExecutor<String, String> create(RequestHttp requestHttp){ | |||
| switch (requestHttp.getRequestType()){ | |||
| public static RequestExecutor<String, String> create(RequestHttp requestHttp) { | |||
| switch (requestHttp.getRequestType()) { | |||
| case apacheHttp: | |||
| return new ApacheSimplePostRequestExecutor(requestHttp); | |||
| case joddHttp: | |||
| @@ -1,64 +1,61 @@ | |||
| package me.chanjar.weixin.common.util.http; | |||
| import org.apache.http.conn.DnsResolver; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| import java.net.InetAddress; | |||
| import java.net.UnknownHostException; | |||
| import java.util.HashMap; | |||
| import java.util.Map; | |||
| import org.apache.http.conn.DnsResolver; | |||
| import org.slf4j.Logger; | |||
| import org.slf4j.LoggerFactory; | |||
| /** | |||
| * 微信DNS域名解析器,将微信域名绑定到指定IP | |||
| * -------------------------------------------- | |||
| * 适用于服务器端调用微信服务器需要开通出口防火墙情况 | |||
| * | |||
| * <p> | |||
| * Created by Andy Huo on 17/03/28. | |||
| */ | |||
| public class WxDnsResolver implements DnsResolver { | |||
| protected final Logger log = LoggerFactory.getLogger(WxDnsResolver.class); | |||
| private static Map<String, InetAddress[]> MAPPINGS = new HashMap<String, InetAddress[]>(); | |||
| private final static String WECHAT_API_URL = "api.weixin.qq.com"; | |||
| private String wxApiIp; | |||
| public WxDnsResolver(String ip){ | |||
| this.wxApiIp = ip; | |||
| this.init(); | |||
| } | |||
| private void init(){ | |||
| if(log.isDebugEnabled()){ | |||
| log.debug("init wechat dns config with ip {}", wxApiIp); | |||
| } | |||
| try { | |||
| MAPPINGS.put(WECHAT_API_URL, new InetAddress[]{InetAddress.getByName(wxApiIp)}); | |||
| } catch (UnknownHostException e) { | |||
| //如果初始化DNS配置失败则使用默认配置,不影响服务的启动 | |||
| log.error("init WxDnsResolver error", e); | |||
| MAPPINGS = new HashMap<String, InetAddress[]>(); | |||
| } | |||
| } | |||
| @Override | |||
| public InetAddress[] resolve(String host) throws UnknownHostException { | |||
| return MAPPINGS.containsKey(host) ? MAPPINGS.get(host) : new InetAddress[0]; | |||
| } | |||
| private final static String WECHAT_API_URL = "api.weixin.qq.com"; | |||
| private static Map<String, InetAddress[]> MAPPINGS = new HashMap<String, InetAddress[]>(); | |||
| protected final Logger log = LoggerFactory.getLogger(WxDnsResolver.class); | |||
| private String wxApiIp; | |||
| public WxDnsResolver(String ip) { | |||
| this.wxApiIp = ip; | |||
| this.init(); | |||
| } | |||
| private void init() { | |||
| if (log.isDebugEnabled()) { | |||
| log.debug("init wechat dns config with ip {}", wxApiIp); | |||
| } | |||
| try { | |||
| MAPPINGS.put(WECHAT_API_URL, new InetAddress[]{InetAddress.getByName(wxApiIp)}); | |||
| } catch (UnknownHostException e) { | |||
| //如果初始化DNS配置失败则使用默认配置,不影响服务的启动 | |||
| log.error("init WxDnsResolver error", e); | |||
| MAPPINGS = new HashMap<String, InetAddress[]>(); | |||
| } | |||
| } | |||
| @Override | |||
| public InetAddress[] resolve(String host) throws UnknownHostException { | |||
| return MAPPINGS.containsKey(host) ? MAPPINGS.get(host) : new InetAddress[0]; | |||
| } | |||
| public String getWxApiIp() { | |||
| return wxApiIp; | |||
| } | |||
| public String getWxApiIp() { | |||
| return wxApiIp; | |||
| } | |||
| public void setWxApiIp(String wxApiIp) { | |||
| this.wxApiIp = wxApiIp; | |||
| this.init(); | |||
| } | |||
| public void setWxApiIp(String wxApiIp) { | |||
| this.wxApiIp = wxApiIp; | |||
| this.init(); | |||
| } | |||
| } | |||
| @@ -5,6 +5,7 @@ import org.apache.http.impl.client.CloseableHttpClient; | |||
| /** | |||
| * httpclient build interface | |||
| * | |||
| * @author kakotor | |||
| */ | |||
| public interface ApacheHttpClientBuilder { | |||
| @@ -30,285 +30,277 @@ import java.util.concurrent.atomic.AtomicBoolean; | |||
| /** | |||
| * httpclient 连接管理器 自带DNS解析 | |||
| * | |||
| * <p> | |||
| * 大部分代码拷贝自:DefaultApacheHttpClientBuilder | |||
| * | |||
| * @author Andy.Huo | |||
| */ | |||
| @NotThreadSafe | |||
| public class ApacheHttpDnsClientBuilder implements ApacheHttpClientBuilder { | |||
| protected final Logger log = LoggerFactory.getLogger(ApacheHttpDnsClientBuilder.class); | |||
| private final AtomicBoolean prepared = new AtomicBoolean(false); | |||
| private int connectionRequestTimeout = 3000; | |||
| private int connectionTimeout = 5000; | |||
| private int soTimeout = 5000; | |||
| private int idleConnTimeout = 60000; | |||
| private int checkWaitTime = 60000; | |||
| private int maxConnPerHost = 10; | |||
| private int maxTotalConn = 50; | |||
| private String userAgent; | |||
| private DnsResolver dnsResover; | |||
| private HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { | |||
| @Override | |||
| public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { | |||
| return false; | |||
| } | |||
| }; | |||
| private SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory(); | |||
| private PlainConnectionSocketFactory plainConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory(); | |||
| private String httpProxyHost; | |||
| private int httpProxyPort; | |||
| private String httpProxyUsername; | |||
| private String httpProxyPassword; | |||
| /** | |||
| * 闲置连接监控线程 | |||
| */ | |||
| private IdleConnectionMonitorThread idleConnectionMonitorThread; | |||
| private HttpClientBuilder httpClientBuilder; | |||
| private ApacheHttpDnsClientBuilder() { | |||
| } | |||
| public static ApacheHttpDnsClientBuilder get() { | |||
| return new ApacheHttpDnsClientBuilder(); | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder httpProxyHost(String httpProxyHost) { | |||
| this.httpProxyHost = httpProxyHost; | |||
| return this; | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder httpProxyPort(int httpProxyPort) { | |||
| this.httpProxyPort = httpProxyPort; | |||
| return this; | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername) { | |||
| this.httpProxyUsername = httpProxyUsername; | |||
| return this; | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword) { | |||
| this.httpProxyPassword = httpProxyPassword; | |||
| return this; | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory) { | |||
| this.sslConnectionSocketFactory = sslConnectionSocketFactory; | |||
| return this; | |||
| } | |||
| /** | |||
| * 获取链接的超时时间设置,默认3000ms | |||
| * <p> | |||
| * 设置为零时不超时,一直等待. 设置为负数是使用系统默认设置(非上述的3000ms的默认值,而是httpclient的默认设置). | |||
| * </p> | |||
| * | |||
| * @param connectionRequestTimeout | |||
| * 获取链接的超时时间设置(单位毫秒),默认3000ms | |||
| */ | |||
| public void setConnectionRequestTimeout(int connectionRequestTimeout) { | |||
| this.connectionRequestTimeout = connectionRequestTimeout; | |||
| } | |||
| /** | |||
| * 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用 | |||
| * <p> | |||
| * 设置为零时不超时,一直等待. 设置为负数是使用系统默认设置(非上述的5000ms的默认值,而是httpclient的默认设置). | |||
| * </p> | |||
| * | |||
| * @param connectionTimeout | |||
| * 建立链接的超时时间设置(单位毫秒),默认5000ms | |||
| */ | |||
| public void setConnectionTimeout(int connectionTimeout) { | |||
| this.connectionTimeout = connectionTimeout; | |||
| } | |||
| /** | |||
| * 默认NIO的socket超时设置,默认5000ms. | |||
| * | |||
| * @param soTimeout | |||
| * 默认NIO的socket超时设置,默认5000ms. | |||
| * @see java.net.SocketOptions#SO_TIMEOUT | |||
| */ | |||
| public void setSoTimeout(int soTimeout) { | |||
| this.soTimeout = soTimeout; | |||
| } | |||
| /** | |||
| * 空闲链接的超时时间,默认60000ms. | |||
| * <p> | |||
| * 超时的链接将在下一次空闲链接检查是被销毁 | |||
| * </p> | |||
| * | |||
| * @param idleConnTimeout | |||
| * 空闲链接的超时时间,默认60000ms. | |||
| */ | |||
| public void setIdleConnTimeout(int idleConnTimeout) { | |||
| this.idleConnTimeout = idleConnTimeout; | |||
| } | |||
| /** | |||
| * 检查空间链接的间隔周期,默认60000ms. | |||
| * | |||
| * @param checkWaitTime | |||
| * 检查空间链接的间隔周期,默认60000ms. | |||
| */ | |||
| public void setCheckWaitTime(int checkWaitTime) { | |||
| this.checkWaitTime = checkWaitTime; | |||
| } | |||
| /** | |||
| * 每路的最大链接数,默认10 | |||
| * | |||
| * @param maxConnPerHost | |||
| * 每路的最大链接数,默认10 | |||
| */ | |||
| public void setMaxConnPerHost(int maxConnPerHost) { | |||
| this.maxConnPerHost = maxConnPerHost; | |||
| } | |||
| /** | |||
| * 最大总连接数,默认50 | |||
| * | |||
| * @param maxTotalConn | |||
| * 最大总连接数,默认50 | |||
| */ | |||
| public void setMaxTotalConn(int maxTotalConn) { | |||
| this.maxTotalConn = maxTotalConn; | |||
| } | |||
| /** | |||
| * 自定义httpclient的User Agent | |||
| * | |||
| * @param userAgent | |||
| * User Agent | |||
| */ | |||
| public void setUserAgent(String userAgent) { | |||
| this.userAgent = userAgent; | |||
| } | |||
| public IdleConnectionMonitorThread getIdleConnectionMonitorThread() { | |||
| return this.idleConnectionMonitorThread; | |||
| } | |||
| private synchronized void prepare() { | |||
| if (prepared.get()) { | |||
| return; | |||
| } | |||
| Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() | |||
| .register("http", this.plainConnectionSocketFactory).register("https", this.sslConnectionSocketFactory) | |||
| .build(); | |||
| @SuppressWarnings("resource") | |||
| PoolingHttpClientConnectionManager connectionManager; | |||
| if(dnsResover != null){ | |||
| if(log.isDebugEnabled()){ | |||
| log.debug("specified dns resolver."); | |||
| } | |||
| connectionManager = new PoolingHttpClientConnectionManager(registry, dnsResover); | |||
| }else{ | |||
| if(log.isDebugEnabled()){ | |||
| log.debug("Not specified dns resolver."); | |||
| } | |||
| connectionManager = new PoolingHttpClientConnectionManager(registry); | |||
| } | |||
| connectionManager.setMaxTotal(this.maxTotalConn); | |||
| connectionManager.setDefaultMaxPerRoute(this.maxConnPerHost); | |||
| connectionManager | |||
| .setDefaultSocketConfig(SocketConfig.copy(SocketConfig.DEFAULT).setSoTimeout(this.soTimeout).build()); | |||
| this.idleConnectionMonitorThread = new IdleConnectionMonitorThread(connectionManager, this.idleConnTimeout, | |||
| this.checkWaitTime); | |||
| this.idleConnectionMonitorThread.setDaemon(true); | |||
| this.idleConnectionMonitorThread.start(); | |||
| this.httpClientBuilder = HttpClients.custom().setConnectionManager(connectionManager) | |||
| .setConnectionManagerShared(true) | |||
| .setDefaultRequestConfig(RequestConfig.custom().setSocketTimeout(this.soTimeout) | |||
| .setConnectTimeout(this.connectionTimeout) | |||
| .setConnectionRequestTimeout(this.connectionRequestTimeout).build()) | |||
| .setRetryHandler(this.httpRequestRetryHandler); | |||
| if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) { | |||
| // 使用代理服务器 需要用户认证的代理服务器 | |||
| CredentialsProvider provider = new BasicCredentialsProvider(); | |||
| provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort), | |||
| new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); | |||
| this.httpClientBuilder.setDefaultCredentialsProvider(provider); | |||
| } | |||
| if (StringUtils.isNotBlank(this.userAgent)) { | |||
| this.httpClientBuilder.setUserAgent(this.userAgent); | |||
| } | |||
| prepared.set(true); | |||
| } | |||
| @Override | |||
| public CloseableHttpClient build() { | |||
| if (!prepared.get()) { | |||
| prepare(); | |||
| } | |||
| return this.httpClientBuilder.build(); | |||
| } | |||
| public static class IdleConnectionMonitorThread extends Thread { | |||
| private final HttpClientConnectionManager connMgr; | |||
| private final int idleConnTimeout; | |||
| private final int checkWaitTime; | |||
| private volatile boolean shutdown; | |||
| public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, | |||
| int checkWaitTime) { | |||
| super("IdleConnectionMonitorThread"); | |||
| this.connMgr = connMgr; | |||
| this.idleConnTimeout = idleConnTimeout; | |||
| this.checkWaitTime = checkWaitTime; | |||
| } | |||
| @Override | |||
| public void run() { | |||
| try { | |||
| while (!this.shutdown) { | |||
| synchronized (this) { | |||
| wait(this.checkWaitTime); | |||
| this.connMgr.closeExpiredConnections(); | |||
| this.connMgr.closeIdleConnections(this.idleConnTimeout, TimeUnit.MILLISECONDS); | |||
| } | |||
| } | |||
| } catch (InterruptedException ignore) { | |||
| } | |||
| } | |||
| public void trigger() { | |||
| synchronized (this) { | |||
| notifyAll(); | |||
| } | |||
| } | |||
| public void shutdown() { | |||
| this.shutdown = true; | |||
| synchronized (this) { | |||
| notifyAll(); | |||
| } | |||
| } | |||
| } | |||
| public DnsResolver getDnsResover() { | |||
| return dnsResover; | |||
| } | |||
| public void setDnsResover(DnsResolver dnsResover) { | |||
| this.dnsResover = dnsResover; | |||
| } | |||
| protected final Logger log = LoggerFactory.getLogger(ApacheHttpDnsClientBuilder.class); | |||
| private final AtomicBoolean prepared = new AtomicBoolean(false); | |||
| private int connectionRequestTimeout = 3000; | |||
| private int connectionTimeout = 5000; | |||
| private int soTimeout = 5000; | |||
| private int idleConnTimeout = 60000; | |||
| private int checkWaitTime = 60000; | |||
| private int maxConnPerHost = 10; | |||
| private int maxTotalConn = 50; | |||
| private String userAgent; | |||
| private DnsResolver dnsResover; | |||
| private HttpRequestRetryHandler httpRequestRetryHandler = new HttpRequestRetryHandler() { | |||
| @Override | |||
| public boolean retryRequest(IOException exception, int executionCount, HttpContext context) { | |||
| return false; | |||
| } | |||
| }; | |||
| private SSLConnectionSocketFactory sslConnectionSocketFactory = SSLConnectionSocketFactory.getSocketFactory(); | |||
| private PlainConnectionSocketFactory plainConnectionSocketFactory = PlainConnectionSocketFactory.getSocketFactory(); | |||
| private String httpProxyHost; | |||
| private int httpProxyPort; | |||
| private String httpProxyUsername; | |||
| private String httpProxyPassword; | |||
| /** | |||
| * 闲置连接监控线程 | |||
| */ | |||
| private IdleConnectionMonitorThread idleConnectionMonitorThread; | |||
| private HttpClientBuilder httpClientBuilder; | |||
| private ApacheHttpDnsClientBuilder() { | |||
| } | |||
| public static ApacheHttpDnsClientBuilder get() { | |||
| return new ApacheHttpDnsClientBuilder(); | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder httpProxyHost(String httpProxyHost) { | |||
| this.httpProxyHost = httpProxyHost; | |||
| return this; | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder httpProxyPort(int httpProxyPort) { | |||
| this.httpProxyPort = httpProxyPort; | |||
| return this; | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder httpProxyUsername(String httpProxyUsername) { | |||
| this.httpProxyUsername = httpProxyUsername; | |||
| return this; | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder httpProxyPassword(String httpProxyPassword) { | |||
| this.httpProxyPassword = httpProxyPassword; | |||
| return this; | |||
| } | |||
| @Override | |||
| public ApacheHttpClientBuilder sslConnectionSocketFactory(SSLConnectionSocketFactory sslConnectionSocketFactory) { | |||
| this.sslConnectionSocketFactory = sslConnectionSocketFactory; | |||
| return this; | |||
| } | |||
| /** | |||
| * 获取链接的超时时间设置,默认3000ms | |||
| * <p> | |||
| * 设置为零时不超时,一直等待. 设置为负数是使用系统默认设置(非上述的3000ms的默认值,而是httpclient的默认设置). | |||
| * </p> | |||
| * | |||
| * @param connectionRequestTimeout 获取链接的超时时间设置(单位毫秒),默认3000ms | |||
| */ | |||
| public void setConnectionRequestTimeout(int connectionRequestTimeout) { | |||
| this.connectionRequestTimeout = connectionRequestTimeout; | |||
| } | |||
| /** | |||
| * 建立链接的超时时间,默认为5000ms.由于是在链接池获取链接,此设置应该并不起什么作用 | |||
| * <p> | |||
| * 设置为零时不超时,一直等待. 设置为负数是使用系统默认设置(非上述的5000ms的默认值,而是httpclient的默认设置). | |||
| * </p> | |||
| * | |||
| * @param connectionTimeout 建立链接的超时时间设置(单位毫秒),默认5000ms | |||
| */ | |||
| public void setConnectionTimeout(int connectionTimeout) { | |||
| this.connectionTimeout = connectionTimeout; | |||
| } | |||
| /** | |||
| * 默认NIO的socket超时设置,默认5000ms. | |||
| * | |||
| * @param soTimeout 默认NIO的socket超时设置,默认5000ms. | |||
| * @see java.net.SocketOptions#SO_TIMEOUT | |||
| */ | |||
| public void setSoTimeout(int soTimeout) { | |||
| this.soTimeout = soTimeout; | |||
| } | |||
| /** | |||
| * 空闲链接的超时时间,默认60000ms. | |||
| * <p> | |||
| * 超时的链接将在下一次空闲链接检查是被销毁 | |||
| * </p> | |||
| * | |||
| * @param idleConnTimeout 空闲链接的超时时间,默认60000ms. | |||
| */ | |||
| public void setIdleConnTimeout(int idleConnTimeout) { | |||
| this.idleConnTimeout = idleConnTimeout; | |||
| } | |||
| /** | |||
| * 检查空间链接的间隔周期,默认60000ms. | |||
| * | |||
| * @param checkWaitTime 检查空间链接的间隔周期,默认60000ms. | |||
| */ | |||
| public void setCheckWaitTime(int checkWaitTime) { | |||
| this.checkWaitTime = checkWaitTime; | |||
| } | |||
| /** | |||
| * 每路的最大链接数,默认10 | |||
| * | |||
| * @param maxConnPerHost 每路的最大链接数,默认10 | |||
| */ | |||
| public void setMaxConnPerHost(int maxConnPerHost) { | |||
| this.maxConnPerHost = maxConnPerHost; | |||
| } | |||
| /** | |||
| * 最大总连接数,默认50 | |||
| * | |||
| * @param maxTotalConn 最大总连接数,默认50 | |||
| */ | |||
| public void setMaxTotalConn(int maxTotalConn) { | |||
| this.maxTotalConn = maxTotalConn; | |||
| } | |||
| /** | |||
| * 自定义httpclient的User Agent | |||
| * | |||
| * @param userAgent User Agent | |||
| */ | |||
| public void setUserAgent(String userAgent) { | |||
| this.userAgent = userAgent; | |||
| } | |||
| public IdleConnectionMonitorThread getIdleConnectionMonitorThread() { | |||
| return this.idleConnectionMonitorThread; | |||
| } | |||
| private synchronized void prepare() { | |||
| if (prepared.get()) { | |||
| return; | |||
| } | |||
| Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() | |||
| .register("http", this.plainConnectionSocketFactory).register("https", this.sslConnectionSocketFactory) | |||
| .build(); | |||
| @SuppressWarnings("resource") | |||
| PoolingHttpClientConnectionManager connectionManager; | |||
| if (dnsResover != null) { | |||
| if (log.isDebugEnabled()) { | |||
| log.debug("specified dns resolver."); | |||
| } | |||
| connectionManager = new PoolingHttpClientConnectionManager(registry, dnsResover); | |||
| } else { | |||
| if (log.isDebugEnabled()) { | |||
| log.debug("Not specified dns resolver."); | |||
| } | |||
| connectionManager = new PoolingHttpClientConnectionManager(registry); | |||
| } | |||
| connectionManager.setMaxTotal(this.maxTotalConn); | |||
| connectionManager.setDefaultMaxPerRoute(this.maxConnPerHost); | |||
| connectionManager | |||
| .setDefaultSocketConfig(SocketConfig.copy(SocketConfig.DEFAULT).setSoTimeout(this.soTimeout).build()); | |||
| this.idleConnectionMonitorThread = new IdleConnectionMonitorThread(connectionManager, this.idleConnTimeout, | |||
| this.checkWaitTime); | |||
| this.idleConnectionMonitorThread.setDaemon(true); | |||
| this.idleConnectionMonitorThread.start(); | |||
| this.httpClientBuilder = HttpClients.custom().setConnectionManager(connectionManager) | |||
| .setConnectionManagerShared(true) | |||
| .setDefaultRequestConfig(RequestConfig.custom().setSocketTimeout(this.soTimeout) | |||
| .setConnectTimeout(this.connectionTimeout) | |||
| .setConnectionRequestTimeout(this.connectionRequestTimeout).build()) | |||
| .setRetryHandler(this.httpRequestRetryHandler); | |||
| if (StringUtils.isNotBlank(this.httpProxyHost) && StringUtils.isNotBlank(this.httpProxyUsername)) { | |||
| // 使用代理服务器 需要用户认证的代理服务器 | |||
| CredentialsProvider provider = new BasicCredentialsProvider(); | |||
| provider.setCredentials(new AuthScope(this.httpProxyHost, this.httpProxyPort), | |||
| new UsernamePasswordCredentials(this.httpProxyUsername, this.httpProxyPassword)); | |||
| this.httpClientBuilder.setDefaultCredentialsProvider(provider); | |||
| } | |||
| if (StringUtils.isNotBlank(this.userAgent)) { | |||
| this.httpClientBuilder.setUserAgent(this.userAgent); | |||
| } | |||
| prepared.set(true); | |||
| } | |||
| @Override | |||
| public CloseableHttpClient build() { | |||
| if (!prepared.get()) { | |||
| prepare(); | |||
| } | |||
| return this.httpClientBuilder.build(); | |||
| } | |||
| public DnsResolver getDnsResover() { | |||
| return dnsResover; | |||
| } | |||
| public void setDnsResover(DnsResolver dnsResover) { | |||
| this.dnsResover = dnsResover; | |||
| } | |||
| public static class IdleConnectionMonitorThread extends Thread { | |||
| private final HttpClientConnectionManager connMgr; | |||
| private final int idleConnTimeout; | |||
| private final int checkWaitTime; | |||
| private volatile boolean shutdown; | |||
| public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr, int idleConnTimeout, | |||
| int checkWaitTime) { | |||
| super("IdleConnectionMonitorThread"); | |||
| this.connMgr = connMgr; | |||
| this.idleConnTimeout = idleConnTimeout; | |||
| this.checkWaitTime = checkWaitTime; | |||
| } | |||
| @Override | |||
| public void run() { | |||
| try { | |||
| while (!this.shutdown) { | |||
| synchronized (this) { | |||
| wait(this.checkWaitTime); | |||
| this.connMgr.closeExpiredConnections(); | |||
| this.connMgr.closeIdleConnections(this.idleConnTimeout, TimeUnit.MILLISECONDS); | |||
| } | |||
| } | |||
| } catch (InterruptedException ignore) { | |||
| } | |||
| } | |||
| public void trigger() { | |||
| synchronized (this) { | |||
| notifyAll(); | |||
| } | |||
| } | |||
| public void shutdown() { | |||
| this.shutdown = true; | |||
| synchronized (this) { | |||
| notifyAll(); | |||
| } | |||
| } | |||
| } | |||
| } | |||
| @@ -1,11 +1,10 @@ | |||
| package me.chanjar.weixin.common.util.http.apache; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| 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.RequestHttp; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.apache.http.Header; | |||
| import org.apache.http.HttpHost; | |||
| @@ -15,13 +14,11 @@ import org.apache.http.client.methods.HttpGet; | |||
| import org.apache.http.entity.ContentType; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| 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.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| /** | |||
| * Created by ecoolper on 2017/5/5. | |||
| @@ -1,8 +1,10 @@ | |||
| package me.chanjar.weixin.common.util.http.apache; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| 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.http.MediaUploadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import org.apache.http.HttpEntity; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.client.config.RequestConfig; | |||
| @@ -13,12 +15,8 @@ import org.apache.http.entity.mime.HttpMultipartMode; | |||
| import org.apache.http.entity.mime.MultipartEntityBuilder; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| 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.http.MediaUploadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/5. | |||
| @@ -1,18 +1,16 @@ | |||
| package me.chanjar.weixin.common.util.http.apache; | |||
| import java.io.IOException; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.client.config.RequestConfig; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.client.methods.HttpGet; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/4. | |||
| @@ -1,7 +1,9 @@ | |||
| package me.chanjar.weixin.common.util.http.apache; | |||
| import java.io.IOException; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | |||
| import org.apache.http.Consts; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.client.config.RequestConfig; | |||
| @@ -10,11 +12,7 @@ import org.apache.http.client.methods.HttpPost; | |||
| import org.apache.http.entity.StringEntity; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/4. | |||
| @@ -188,7 +188,7 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder { | |||
| } | |||
| private synchronized void prepare() { | |||
| if(prepared.get()){ | |||
| if (prepared.get()) { | |||
| return; | |||
| } | |||
| Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create() | |||
| @@ -242,7 +242,7 @@ public class DefaultApacheHttpClientBuilder implements ApacheHttpClientBuilder { | |||
| @Override | |||
| public CloseableHttpClient build() { | |||
| if(!prepared.get()){ | |||
| if (!prepared.get()) { | |||
| prepare(); | |||
| } | |||
| return this.httpClientBuilder.build(); | |||
| @@ -1,14 +1,5 @@ | |||
| package me.chanjar.weixin.common.util.http.jodd; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| @@ -17,8 +8,15 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||
| 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.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| /** | |||
| * Created by ecoolper on 2017/5/5. | |||
| @@ -1,8 +1,5 @@ | |||
| package me.chanjar.weixin.common.util.http.jodd; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| @@ -11,9 +8,11 @@ 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.http.MediaUploadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/5. | |||
| */ | |||
| @@ -1,23 +1,15 @@ | |||
| package me.chanjar.weixin.common.util.http.jodd; | |||
| import java.io.IOException; | |||
| import org.apache.http.HttpHost; | |||
| import org.apache.http.client.config.RequestConfig; | |||
| import org.apache.http.client.methods.CloseableHttpResponse; | |||
| import org.apache.http.client.methods.HttpGet; | |||
| import org.apache.http.impl.client.CloseableHttpClient; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| import jodd.http.ProxyInfo; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.apache.Utf8ResponseHandler; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/4. | |||
| @@ -1,17 +1,16 @@ | |||
| package me.chanjar.weixin.common.util.http.jodd; | |||
| import java.io.IOException; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| import jodd.http.ProxyInfo; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/4. | |||
| */ | |||
| @@ -24,7 +23,7 @@ public class JoddSimplePostRequestExecutor extends SimplePostRequestExecutor<Htt | |||
| @Override | |||
| public String execute(String uri, String postEntity) throws WxErrorException, IOException { | |||
| HttpConnectionProvider provider = requestHttp.getRequestHttpClient(); | |||
| ProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); | |||
| ProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); | |||
| HttpRequest request = HttpRequest.post(uri); | |||
| if (proxyInfo != null) { | |||
| @@ -1,22 +1,19 @@ | |||
| package me.chanjar.weixin.common.util.http.okhttp; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| 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.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import okhttp3.*; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import java.io.ByteArrayInputStream; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.regex.Matcher; | |||
| import java.util.regex.Pattern; | |||
| /** | |||
| * Created by ecoolper on 2017/5/5. | |||
| @@ -1,16 +1,15 @@ | |||
| package me.chanjar.weixin.common.util.http.okhttp; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| 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.http.MediaUploadRequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import okhttp3.*; | |||
| import java.io.File; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/5. | |||
| */ | |||
| @@ -1,18 +1,13 @@ | |||
| package me.chanjar.weixin.common.util.http.okhttp; | |||
| import java.io.IOException; | |||
| import jodd.http.HttpConnectionProvider; | |||
| import jodd.http.HttpRequest; | |||
| import jodd.http.HttpResponse; | |||
| import jodd.http.ProxyInfo; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import me.chanjar.weixin.common.util.http.SimpleGetRequestExecutor; | |||
| import okhttp3.*; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/4. | |||
| */ | |||
| @@ -47,7 +42,7 @@ public class OkSimpleGetRequestExecutor extends SimpleGetRequestExecutor<Connect | |||
| } | |||
| }); | |||
| //得到httpClient | |||
| OkHttpClient client =clientBuilder.build(); | |||
| OkHttpClient client = clientBuilder.build(); | |||
| Request request = new Request.Builder().url(uri).build(); | |||
| @@ -1,26 +1,25 @@ | |||
| package me.chanjar.weixin.common.util.http.okhttp; | |||
| import java.io.IOException; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.common.util.http.RequestHttp; | |||
| import me.chanjar.weixin.common.util.http.SimplePostRequestExecutor; | |||
| import okhttp3.*; | |||
| import java.io.IOException; | |||
| /** | |||
| * Created by ecoolper on 2017/5/4. | |||
| */ | |||
| public class OkSimplePostRequestExecutor extends SimplePostRequestExecutor<ConnectionPool,OkhttpProxyInfo>{ | |||
| public class OkSimplePostRequestExecutor extends SimplePostRequestExecutor<ConnectionPool, OkhttpProxyInfo> { | |||
| public OkSimplePostRequestExecutor(RequestHttp requestHttp) { | |||
| super(requestHttp); | |||
| } | |||
| @Override | |||
| public String execute(String uri, String postEntity) throws WxErrorException, IOException { | |||
| ConnectionPool pool = requestHttp.getRequestHttpClient(); | |||
| public String execute(String uri, String postEntity) throws WxErrorException, IOException { | |||
| ConnectionPool pool = requestHttp.getRequestHttpClient(); | |||
| final OkhttpProxyInfo proxyInfo = requestHttp.getRequestHttpProxy(); | |||
| OkHttpClient.Builder clientBuilder = new OkHttpClient.Builder().connectionPool(pool); | |||
| @@ -8,19 +8,11 @@ import java.net.Proxy; | |||
| * Proxy information. | |||
| */ | |||
| public class OkhttpProxyInfo { | |||
| /** | |||
| * Proxy types. | |||
| */ | |||
| public enum ProxyType { | |||
| NONE, HTTP, SOCKS4, SOCKS5 | |||
| } | |||
| private final String proxyAddress; | |||
| private final int proxyPort; | |||
| private final String proxyUsername; | |||
| private final String proxyPassword; | |||
| private final ProxyType proxyType; | |||
| public OkhttpProxyInfo(ProxyType proxyType, String proxyHost, int proxyPort, String proxyUser, String proxyPassword) { | |||
| this.proxyType = proxyType; | |||
| this.proxyAddress = proxyHost; | |||
| @@ -29,8 +21,6 @@ public class OkhttpProxyInfo { | |||
| this.proxyPassword = proxyPassword; | |||
| } | |||
| // ---------------------------------------------------------------- factory | |||
| /** | |||
| * Creates directProxy. | |||
| */ | |||
| @@ -38,6 +28,8 @@ public class OkhttpProxyInfo { | |||
| return new OkhttpProxyInfo(ProxyType.NONE, null, 0, null, null); | |||
| } | |||
| // ---------------------------------------------------------------- factory | |||
| /** | |||
| * Creates SOCKS4 proxy. | |||
| */ | |||
| @@ -59,8 +51,6 @@ public class OkhttpProxyInfo { | |||
| return new OkhttpProxyInfo(ProxyType.HTTP, proxyAddress, proxyPort, proxyUser, proxyPassword); | |||
| } | |||
| // ---------------------------------------------------------------- getter | |||
| /** | |||
| * Returns proxy type. | |||
| */ | |||
| @@ -68,6 +58,8 @@ public class OkhttpProxyInfo { | |||
| return proxyType; | |||
| } | |||
| // ---------------------------------------------------------------- getter | |||
| /** | |||
| * Returns proxy address. | |||
| */ | |||
| @@ -99,6 +91,7 @@ public class OkhttpProxyInfo { | |||
| /** | |||
| * 返回 java.net.Proxy | |||
| * | |||
| * @return | |||
| */ | |||
| public Proxy getProxy() { | |||
| @@ -114,4 +107,11 @@ public class OkhttpProxyInfo { | |||
| } | |||
| return proxy; | |||
| } | |||
| /** | |||
| * Proxy types. | |||
| */ | |||
| public enum ProxyType { | |||
| NONE, HTTP, SOCKS4, SOCKS5 | |||
| } | |||
| } | |||
| @@ -2,7 +2,6 @@ package me.chanjar.weixin.common.util.json; | |||
| import com.google.gson.Gson; | |||
| import com.google.gson.GsonBuilder; | |||
| import me.chanjar.weixin.common.bean.WxAccessToken; | |||
| import me.chanjar.weixin.common.bean.menu.WxMenu; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| @@ -47,7 +47,7 @@ import java.util.*; | |||
| public class StringManager { | |||
| private static final Map<String, Map<Locale, StringManager>> managers = | |||
| new Hashtable<>(); | |||
| new Hashtable<>(); | |||
| private static int LOCALE_CACHE_SIZE = 10; | |||
| /** | |||
| * The ResourceBundle for this StringManager. | |||
| @@ -103,7 +103,7 @@ public class StringManager { | |||
| * @param packageName The package name | |||
| */ | |||
| public static final synchronized StringManager getManager( | |||
| String packageName) { | |||
| String packageName) { | |||
| return getManager(packageName, Locale.getDefault()); | |||
| } | |||
| @@ -116,7 +116,7 @@ public class StringManager { | |||
| * @param locale The Locale | |||
| */ | |||
| public static final synchronized StringManager getManager( | |||
| String packageName, Locale locale) { | |||
| String packageName, Locale locale) { | |||
| Map<Locale, StringManager> map = managers.get(packageName); | |||
| if (map == null) { | |||
| @@ -133,7 +133,7 @@ public class StringManager { | |||
| @Override | |||
| protected boolean removeEldestEntry( | |||
| Map.Entry<Locale, StringManager> eldest) { | |||
| Map.Entry<Locale, StringManager> eldest) { | |||
| return size() > (LOCALE_CACHE_SIZE - 1); | |||
| } | |||
| }; | |||
| @@ -1,7 +1,5 @@ | |||
| package me.chanjar.weixin.common.util.xml; | |||
| import java.io.Writer; | |||
| import com.thoughtworks.xstream.XStream; | |||
| import com.thoughtworks.xstream.core.util.QuickWriter; | |||
| import com.thoughtworks.xstream.io.HierarchicalStreamWriter; | |||
| @@ -10,6 +8,8 @@ import com.thoughtworks.xstream.io.xml.XppDriver; | |||
| import com.thoughtworks.xstream.security.NullPermission; | |||
| import com.thoughtworks.xstream.security.PrimitiveTypePermission; | |||
| import java.io.Writer; | |||
| public class XStreamInitializer { | |||
| public static XStream getInstance() { | |||
| @@ -1,7 +1,7 @@ | |||
| package me.chanjar.weixin.common.bean; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxAccessTokenTest { | |||
| @@ -1,8 +1,8 @@ | |||
| package me.chanjar.weixin.common.bean; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxErrorTest { | |||
| @@ -1,12 +1,10 @@ | |||
| package me.chanjar.weixin.common.bean; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.DataProvider; | |||
| import org.testng.annotations.Test; | |||
| import me.chanjar.weixin.common.bean.menu.WxMenu; | |||
| import me.chanjar.weixin.common.bean.menu.WxMenuButton; | |||
| import me.chanjar.weixin.common.bean.menu.WxMenuRule; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxMenuTest { | |||
| @@ -87,75 +85,75 @@ public class WxMenuTest { | |||
| Object[][] res = menuJson(); | |||
| String json = "{ \"menu\" : " + res[0][0] + " }"; | |||
| return new Object[][]{ | |||
| new Object[]{json} | |||
| new Object[]{json} | |||
| }; | |||
| } | |||
| @DataProvider(name = "wxPushMenu") | |||
| public Object[][] menuJson() { | |||
| String json = | |||
| "{" | |||
| + "\"button\":[" | |||
| + "{" | |||
| + "\"type\":\"click\"," | |||
| + "\"name\":\"今日歌曲\"," | |||
| + "\"key\":\"V1001_TODAY_MUSIC\"" | |||
| + "}," | |||
| + "{" | |||
| + "\"type\":\"click\"," | |||
| + "\"name\":\"歌手简介\"," | |||
| + "\"key\":\"V1001_TODAY_SINGER\"" | |||
| + "}," | |||
| + "{" | |||
| + "\"name\":\"菜单\"," | |||
| + "\"sub_button\":[" | |||
| + "{" | |||
| + "\"type\":\"view\"," | |||
| + "\"name\":\"搜索\"," | |||
| + "\"url\":\"http://www.soso.com/\"" | |||
| + "}," | |||
| + "{" | |||
| + "\"type\":\"view\"," | |||
| + "\"name\":\"视频\"," | |||
| + "\"url\":\"http://v.qq.com/\"" | |||
| + "}," | |||
| + "{" | |||
| + "\"type\":\"click\"," | |||
| + "\"name\":\"赞一下我们\"," | |||
| + "\"key\":\"V1001_GOOD\"" | |||
| + "}" | |||
| + "]" | |||
| + "}" | |||
| + "]" | |||
| + "}"; | |||
| "{" | |||
| + "\"button\":[" | |||
| + "{" | |||
| + "\"type\":\"click\"," | |||
| + "\"name\":\"今日歌曲\"," | |||
| + "\"key\":\"V1001_TODAY_MUSIC\"" | |||
| + "}," | |||
| + "{" | |||
| + "\"type\":\"click\"," | |||
| + "\"name\":\"歌手简介\"," | |||
| + "\"key\":\"V1001_TODAY_SINGER\"" | |||
| + "}," | |||
| + "{" | |||
| + "\"name\":\"菜单\"," | |||
| + "\"sub_button\":[" | |||
| + "{" | |||
| + "\"type\":\"view\"," | |||
| + "\"name\":\"搜索\"," | |||
| + "\"url\":\"http://www.soso.com/\"" | |||
| + "}," | |||
| + "{" | |||
| + "\"type\":\"view\"," | |||
| + "\"name\":\"视频\"," | |||
| + "\"url\":\"http://v.qq.com/\"" | |||
| + "}," | |||
| + "{" | |||
| + "\"type\":\"click\"," | |||
| + "\"name\":\"赞一下我们\"," | |||
| + "\"key\":\"V1001_GOOD\"" | |||
| + "}" | |||
| + "]" | |||
| + "}" | |||
| + "]" | |||
| + "}"; | |||
| return new Object[][]{ | |||
| new Object[]{json} | |||
| new Object[]{json} | |||
| }; | |||
| } | |||
| @DataProvider(name = "wxAddConditionalMenu") | |||
| public Object[][] addConditionalMenuJson() { | |||
| String json = | |||
| "{" | |||
| + "\"button\":[" | |||
| + "{" | |||
| + "\"type\":\"click\"," | |||
| + "\"name\":\"今日歌曲\"," | |||
| + "\"key\":\"V1001_TODAY_MUSIC\"" | |||
| + "}" | |||
| + "]," | |||
| + "\"matchrule\":{" | |||
| + "\"group_id\":\"2\"," | |||
| + "\"sex\":\"1\"," | |||
| + "\"country\":\"中国\"," | |||
| + "\"province\":\"广东\"," | |||
| + "\"city\":\"广州\"," | |||
| + "\"client_platform_type\":\"2\"," | |||
| + "\"language\":\"zh_CN\"" | |||
| + "}" | |||
| + "}"; | |||
| "{" | |||
| + "\"button\":[" | |||
| + "{" | |||
| + "\"type\":\"click\"," | |||
| + "\"name\":\"今日歌曲\"," | |||
| + "\"key\":\"V1001_TODAY_MUSIC\"" | |||
| + "}" | |||
| + "]," | |||
| + "\"matchrule\":{" | |||
| + "\"group_id\":\"2\"," | |||
| + "\"sex\":\"1\"," | |||
| + "\"country\":\"中国\"," | |||
| + "\"province\":\"广东\"," | |||
| + "\"city\":\"广州\"," | |||
| + "\"client_platform_type\":\"2\"," | |||
| + "\"language\":\"zh_CN\"" | |||
| + "}" | |||
| + "}"; | |||
| return new Object[][]{ | |||
| new Object[]{json} | |||
| new Object[]{json} | |||
| }; | |||
| } | |||
| @@ -1,8 +1,7 @@ | |||
| package me.chanjar.weixin.common.session; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.DataProvider; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class SessionTest { | |||
| @@ -11,7 +10,7 @@ public class SessionTest { | |||
| public Object[][] getSessionManager() { | |||
| return new Object[][]{ | |||
| new Object[]{new StandardSessionManager()} | |||
| new Object[]{new StandardSessionManager()} | |||
| }; | |||
| } | |||
| @@ -1,8 +1,8 @@ | |||
| package me.chanjar.weixin.common.util; | |||
| import me.chanjar.weixin.common.api.WxMessageInMemoryDuplicateChecker; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxMessageInMemoryDuplicateCheckerTest { | |||
| @@ -1,6 +1,6 @@ | |||
| package me.chanjar.weixin.common.util.crypto; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.annotations.*; | |||
| import org.w3c.dom.Document; | |||
| import org.w3c.dom.Element; | |||
| import org.w3c.dom.NodeList; | |||
| @@ -13,8 +13,7 @@ import javax.xml.parsers.ParserConfigurationException; | |||
| import java.io.IOException; | |||
| import java.io.StringReader; | |||
| import static org.testng.Assert.assertEquals; | |||
| import static org.testng.Assert.fail; | |||
| import static org.testng.Assert.*; | |||
| @Test | |||
| public class WxCryptUtilTest { | |||
| @@ -77,7 +76,7 @@ public class WxCryptUtilTest { | |||
| } | |||
| public void testValidateSignatureError() throws ParserConfigurationException, SAXException, | |||
| IOException { | |||
| IOException { | |||
| try { | |||
| WxCryptUtil pc = new WxCryptUtil(this.token, this.encodingAesKey, this.appId); | |||
| String afterEncrpt = pc.encrypt(this.replyMsg); | |||
| @@ -10,8 +10,8 @@ | |||
| </appender> | |||
| <root level="info"> | |||
| <appender-ref ref="STDOUT" /> | |||
| <appender-ref ref="STDOUT"/> | |||
| </root> | |||
| <logger name="me.chanjar.weixin.common" level="debug" /> | |||
| <logger name="me.chanjar.weixin.common" level="debug"/> | |||
| </configuration> | |||
| @@ -8,7 +8,7 @@ | |||
| <class name="me.chanjar.weixin.common.bean.WxMenuTest"/> | |||
| <class name="me.chanjar.weixin.common.util.crypto.WxCryptUtilTest"/> | |||
| <class name="me.chanjar.weixin.common.util.WxMessageInMemoryDuplicateCheckerTest"/> | |||
| <class name="me.chanjar.weixin.common.session.SessionTest" /> | |||
| <class name="me.chanjar.weixin.common.session.SessionTest"/> | |||
| </classes> | |||
| </test> | |||
| </suite> | |||
| @@ -1,12 +1,11 @@ | |||
| description = 'WeiXin Java Tools - CP' | |||
| dependencies { | |||
| compile project(':weixin-java-common') | |||
| testCompile group: 'junit', name: 'junit', version:'4.11' | |||
| testCompile group: 'org.testng', name: 'testng', version:'6.8.7' | |||
| testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5' | |||
| testCompile group: 'com.google.inject', name: 'guice', version:'3.0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0' | |||
| testCompile group: 'junit', name: 'junit', version: '4.11' | |||
| testCompile group: 'org.testng', name: 'testng', version: '6.8.7' | |||
| testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' | |||
| testCompile group: 'com.google.inject', name: 'guice', version: '3.0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.0.RC0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.3.0.RC0' | |||
| } | |||
| test.useTestNG() | |||
| @@ -1,7 +1,8 @@ | |||
| <?xml version="1.0"?> | |||
| <project | |||
| 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"> | |||
| 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"> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <parent> | |||
| <groupId>com.github.binarywang</groupId> | |||
| @@ -39,13 +39,13 @@ public class WxCpJedisConfigStorage implements WxCpConfigStorage { | |||
| this.jedisPool = new JedisPool(host, port); | |||
| } | |||
| public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port) { | |||
| this.jedisPool = new JedisPool(poolConfig, host, port); | |||
| this.jedisPool = new JedisPool(poolConfig, host, port); | |||
| } | |||
| public WxCpJedisConfigStorage(JedisPoolConfig poolConfig, String host, int port, int timeout, final String password) { | |||
| this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password); | |||
| this.jedisPool = new JedisPool(poolConfig, host, port, timeout, password); | |||
| } | |||
| /** | |||
| @@ -481,13 +481,6 @@ public interface WxCpService { | |||
| */ | |||
| <T, E> T execute(RequestExecutor<T, E> executor, String uri, E data) throws WxErrorException; | |||
| /** | |||
| * 注入 {@link WxCpConfigStorage} 的实现 | |||
| * | |||
| * @param wxConfigProvider 配置对象 | |||
| */ | |||
| void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider); | |||
| /** | |||
| * <pre> | |||
| * 设置当微信系统响应系统繁忙时,要等待多少 retrySleepMillis(ms) * 2^(重试次数 - 1) 再发起重试 | |||
| @@ -563,4 +556,11 @@ public interface WxCpService { | |||
| * @return WxMpConfigStorage | |||
| */ | |||
| WxCpConfigStorage getWxCpConfigStorage(); | |||
| /** | |||
| * 注入 {@link WxCpConfigStorage} 的实现 | |||
| * | |||
| * @param wxConfigProvider 配置对象 | |||
| */ | |||
| void setWxCpConfigStorage(WxCpConfigStorage wxConfigProvider); | |||
| } | |||
| @@ -1,7 +1,5 @@ | |||
| package me.chanjar.weixin.cp.api.impl.okhttp; | |||
| import java.io.IOException; | |||
| import me.chanjar.weixin.common.bean.WxAccessToken; | |||
| import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| @@ -11,6 +9,8 @@ import me.chanjar.weixin.cp.api.WxCpConfigStorage; | |||
| import me.chanjar.weixin.cp.api.impl.AbstractWxCpServiceImpl; | |||
| import okhttp3.*; | |||
| import java.io.IOException; | |||
| public class WxCpServiceImpl extends AbstractWxCpServiceImpl<ConnectionPool, OkhttpProxyInfo> { | |||
| protected ConnectionPool httpClient; | |||
| protected OkhttpProxyInfo httpProxy; | |||
| @@ -1,9 +1,9 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import java.io.Serializable; | |||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
| import java.io.Serializable; | |||
| /** | |||
| * 微信部门 | |||
| * | |||
| @@ -60,10 +60,10 @@ public class WxCpDepart implements Serializable { | |||
| @Override | |||
| public String toString() { | |||
| return "WxCpDepart{" + | |||
| "id=" + this.id + | |||
| ", name='" + this.name + '\'' + | |||
| ", parentId=" + this.parentId + | |||
| ", order=" + this.order + | |||
| '}'; | |||
| "id=" + this.id + | |||
| ", name='" + this.name + '\'' + | |||
| ", parentId=" + this.parentId + | |||
| ", order=" + this.order + | |||
| '}'; | |||
| } | |||
| } | |||
| @@ -33,14 +33,6 @@ public class WxCpMessage implements Serializable { | |||
| private List<NewArticle> articles = new ArrayList<>(); | |||
| private List<MpnewsArticle> mpnewsArticles = new ArrayList<>(); | |||
| public List<MpnewsArticle> getMpnewsArticles() { | |||
| return mpnewsArticles; | |||
| } | |||
| public void setMpnewsArticles(List<MpnewsArticle> mpnewsArticles) { | |||
| this.mpnewsArticles = mpnewsArticles; | |||
| } | |||
| /** | |||
| * 获得文本消息builder | |||
| */ | |||
| @@ -90,6 +82,14 @@ public class WxCpMessage implements Serializable { | |||
| return new FileBuilder(); | |||
| } | |||
| public List<MpnewsArticle> getMpnewsArticles() { | |||
| return mpnewsArticles; | |||
| } | |||
| public void setMpnewsArticles(List<MpnewsArticle> mpnewsArticles) { | |||
| this.mpnewsArticles = mpnewsArticles; | |||
| } | |||
| public String getToUser() { | |||
| return this.toUser; | |||
| } | |||
| @@ -1,9 +1,9 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import java.io.Serializable; | |||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
| import java.io.Serializable; | |||
| /** | |||
| * Created by Daniel Qian | |||
| */ | |||
| @@ -1,11 +1,11 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
| import java.io.Serializable; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import me.chanjar.weixin.cp.util.json.WxCpGsonBuilder; | |||
| /** | |||
| * 微信用户信息 | |||
| * | |||
| @@ -1,20 +1,18 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.io.Serializable; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import org.apache.commons.io.IOUtils; | |||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
| import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
| import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
| import me.chanjar.weixin.cp.api.WxCpConfigStorage; | |||
| import me.chanjar.weixin.cp.util.crypto.WxCpCryptUtil; | |||
| import me.chanjar.weixin.cp.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> | |||
| @@ -183,18 +181,18 @@ public class WxCpXmlMessage implements Serializable { | |||
| * @param msgSignature | |||
| */ | |||
| public static WxCpXmlMessage fromEncryptedXml( | |||
| String encryptedXml, | |||
| WxCpConfigStorage wxCpConfigStorage, | |||
| String timestamp, String nonce, String msgSignature) { | |||
| String encryptedXml, | |||
| WxCpConfigStorage wxCpConfigStorage, | |||
| String timestamp, String nonce, String msgSignature) { | |||
| WxCpCryptUtil cryptUtil = new WxCpCryptUtil(wxCpConfigStorage); | |||
| String plainText = cryptUtil.decrypt(msgSignature, timestamp, nonce, encryptedXml); | |||
| return fromXml(plainText); | |||
| } | |||
| public static WxCpXmlMessage fromEncryptedXml( | |||
| InputStream is, | |||
| WxCpConfigStorage wxCpConfigStorage, | |||
| String timestamp, String nonce, String msgSignature) { | |||
| InputStream is, | |||
| WxCpConfigStorage wxCpConfigStorage, | |||
| String timestamp, String nonce, String msgSignature) { | |||
| try { | |||
| return fromEncryptedXml(IOUtils.toString(is, "UTF-8"), wxCpConfigStorage, timestamp, nonce, msgSignature); | |||
| } catch (IOException e) { | |||
| @@ -493,40 +491,40 @@ public class WxCpXmlMessage implements Serializable { | |||
| @Override | |||
| public String toString() { | |||
| return "WxCpXmlMessage{" + | |||
| "agentId=" + this.agentId + | |||
| ", toUserName='" + this.toUserName + '\'' + | |||
| ", fromUserName='" + this.fromUserName + '\'' + | |||
| ", createTime=" + this.createTime + | |||
| ", msgType='" + this.msgType + '\'' + | |||
| ", content='" + this.content + '\'' + | |||
| ", msgId=" + this.msgId + | |||
| ", picUrl='" + this.picUrl + '\'' + | |||
| ", mediaId='" + this.mediaId + '\'' + | |||
| ", format='" + this.format + '\'' + | |||
| ", thumbMediaId='" + this.thumbMediaId + '\'' + | |||
| ", locationX=" + this.locationX + | |||
| ", locationY=" + this.locationY + | |||
| ", scale=" + this.scale + | |||
| ", label='" + this.label + '\'' + | |||
| ", title='" + this.title + '\'' + | |||
| ", description='" + this.description + '\'' + | |||
| ", url='" + this.url + '\'' + | |||
| ", event='" + this.event + '\'' + | |||
| ", eventKey='" + this.eventKey + '\'' + | |||
| ", ticket='" + this.ticket + '\'' + | |||
| ", latitude=" + this.latitude + | |||
| ", longitude=" + this.longitude + | |||
| ", precision=" + this.precision + | |||
| ", recognition='" + this.recognition + '\'' + | |||
| ", status='" + this.status + '\'' + | |||
| ", totalCount=" + this.totalCount + | |||
| ", filterCount=" + this.filterCount + | |||
| ", sentCount=" + this.sentCount + | |||
| ", errorCount=" + this.errorCount + | |||
| ", scanCodeInfo=" + this.scanCodeInfo + | |||
| ", sendPicsInfo=" + this.sendPicsInfo + | |||
| ", sendLocationInfo=" + this.sendLocationInfo + | |||
| '}'; | |||
| "agentId=" + this.agentId + | |||
| ", toUserName='" + this.toUserName + '\'' + | |||
| ", fromUserName='" + this.fromUserName + '\'' + | |||
| ", createTime=" + this.createTime + | |||
| ", msgType='" + this.msgType + '\'' + | |||
| ", content='" + this.content + '\'' + | |||
| ", msgId=" + this.msgId + | |||
| ", picUrl='" + this.picUrl + '\'' + | |||
| ", mediaId='" + this.mediaId + '\'' + | |||
| ", format='" + this.format + '\'' + | |||
| ", thumbMediaId='" + this.thumbMediaId + '\'' + | |||
| ", locationX=" + this.locationX + | |||
| ", locationY=" + this.locationY + | |||
| ", scale=" + this.scale + | |||
| ", label='" + this.label + '\'' + | |||
| ", title='" + this.title + '\'' + | |||
| ", description='" + this.description + '\'' + | |||
| ", url='" + this.url + '\'' + | |||
| ", event='" + this.event + '\'' + | |||
| ", eventKey='" + this.eventKey + '\'' + | |||
| ", ticket='" + this.ticket + '\'' + | |||
| ", latitude=" + this.latitude + | |||
| ", longitude=" + this.longitude + | |||
| ", precision=" + this.precision + | |||
| ", recognition='" + this.recognition + '\'' + | |||
| ", status='" + this.status + '\'' + | |||
| ", totalCount=" + this.totalCount + | |||
| ", filterCount=" + this.filterCount + | |||
| ", sentCount=" + this.sentCount + | |||
| ", errorCount=" + this.errorCount + | |||
| ", scanCodeInfo=" + this.scanCodeInfo + | |||
| ", sendPicsInfo=" + this.sendPicsInfo + | |||
| ", sendLocationInfo=" + this.sendLocationInfo + | |||
| '}'; | |||
| } | |||
| @XStreamAlias("ScanCodeInfo") | |||
| @@ -2,7 +2,6 @@ package me.chanjar.weixin.cp.bean; | |||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
| import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter; | |||
| @@ -1,14 +1,13 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
| import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| @XStreamAlias("xml") | |||
| public class WxCpXmlOutNewsMessage extends WxCpXmlOutMessage { | |||
| private static final long serialVersionUID = -5796178637883178826L; | |||
| @@ -2,7 +2,6 @@ package me.chanjar.weixin.cp.bean; | |||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
| import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
| @@ -2,7 +2,6 @@ package me.chanjar.weixin.cp.bean; | |||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
| import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| import me.chanjar.weixin.common.util.xml.XStreamCDataConverter; | |||
| @@ -2,7 +2,6 @@ package me.chanjar.weixin.cp.bean; | |||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
| import com.thoughtworks.xstream.annotations.XStreamConverter; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| import me.chanjar.weixin.common.util.xml.XStreamMediaIdConverter; | |||
| @@ -4,6 +4,7 @@ package me.chanjar.weixin.cp.bean.article; | |||
| * <pre> | |||
| * Created by BinaryWang on 2017/3/27. | |||
| * </pre> | |||
| * | |||
| * @author Binary Wang | |||
| */ | |||
| public class MpnewsArticle { | |||
| @@ -44,7 +44,7 @@ public class BaseBuilder<T> { | |||
| m.setToParty(this.toParty); | |||
| m.setToTag(this.toTag); | |||
| m.setSafe( | |||
| (this.safe == null || "".equals(this.safe)) ? WxConsts.CUSTOM_MSG_SAFE_NO : this.safe); | |||
| (this.safe == null || "".equals(this.safe)) ? WxConsts.CUSTOM_MSG_SAFE_NO : this.safe); | |||
| return m; | |||
| } | |||
| @@ -1,47 +1,51 @@ | |||
| /** | |||
| * 对公众平台发送给公众账号的消息加解密示例代码. | |||
| * | |||
| * @copyright Copyright (c) 1998-2014 Tencent Inc. | |||
| * <p> | |||
| * 针对org.apache.commons.codec.binary.Base64, | |||
| * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | |||
| * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | |||
| */ | |||
| // ------------------------------------------------------------------------ | |||
| /** | |||
| * 针对org.apache.commons.codec.binary.Base64, | |||
| * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | |||
| * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | |||
| */ | |||
| package me.chanjar.weixin.cp.util.crypto; | |||
| import me.chanjar.weixin.common.util.crypto.WxCryptUtil; | |||
| import me.chanjar.weixin.cp.api.WxCpConfigStorage; | |||
| import org.apache.commons.codec.binary.Base64; | |||
| public class WxCpCryptUtil extends WxCryptUtil { | |||
| /** | |||
| * 构造函数 | |||
| * | |||
| * @param wxCpConfigStorage | |||
| */ | |||
| public WxCpCryptUtil(WxCpConfigStorage wxCpConfigStorage) { | |||
| /* | |||
| * @param token 公众平台上,开发者设置的token | |||
| * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey | |||
| * @param appidOrCorpid 公众平台appid | |||
| */ | |||
| String encodingAesKey = wxCpConfigStorage.getAesKey(); | |||
| String token = wxCpConfigStorage.getToken(); | |||
| String corpId = wxCpConfigStorage.getCorpId(); | |||
| this.token = token; | |||
| this.appidOrCorpid = corpId; | |||
| this.aesKey = Base64.decodeBase64(encodingAesKey + "="); | |||
| } | |||
| } | |||
| /** | |||
| * 对公众平台发送给公众账号的消息加解密示例代码. | |||
| * | |||
| * @copyright Copyright (c) 1998-2014 Tencent Inc. | |||
| * <p> | |||
| * 针对org.apache.commons.codec.binary.Base64, | |||
| * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | |||
| * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | |||
| * <p> | |||
| * 针对org.apache.commons.codec.binary.Base64, | |||
| * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | |||
| * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | |||
| */ | |||
| // ------------------------------------------------------------------------ | |||
| /** | |||
| * 针对org.apache.commons.codec.binary.Base64, | |||
| * 需要导入架包commons-codec-1.9(或commons-codec-1.8等其他版本) | |||
| * 官方下载地址:http://commons.apache.org/proper/commons-codec/download_codec.cgi | |||
| */ | |||
| package me.chanjar.weixin.cp.util.crypto; | |||
| import me.chanjar.weixin.common.util.crypto.WxCryptUtil; | |||
| import me.chanjar.weixin.cp.api.WxCpConfigStorage; | |||
| import org.apache.commons.codec.binary.Base64; | |||
| public class WxCpCryptUtil extends WxCryptUtil { | |||
| /** | |||
| * 构造函数 | |||
| * | |||
| * @param wxCpConfigStorage | |||
| */ | |||
| public WxCpCryptUtil(WxCpConfigStorage wxCpConfigStorage) { | |||
| /* | |||
| * @param token 公众平台上,开发者设置的token | |||
| * @param encodingAesKey 公众平台上,开发者设置的EncodingAESKey | |||
| * @param appidOrCorpid 公众平台appid | |||
| */ | |||
| String encodingAesKey = wxCpConfigStorage.getAesKey(); | |||
| String token = wxCpConfigStorage.getToken(); | |||
| String corpId = wxCpConfigStorage.getCorpId(); | |||
| this.token = token; | |||
| this.appidOrCorpid = corpId; | |||
| this.aesKey = Base64.decodeBase64(encodingAesKey + "="); | |||
| } | |||
| } | |||
| @@ -39,7 +39,7 @@ public class WxCpDepartGsonAdapter implements JsonSerializer<WxCpDepart>, JsonDe | |||
| @Override | |||
| public WxCpDepart deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) | |||
| throws JsonParseException { | |||
| throws JsonParseException { | |||
| WxCpDepart depart = new WxCpDepart(); | |||
| JsonObject departJson = json.getAsJsonObject(); | |||
| if (departJson.get("id") != null && !departJson.get("id").isJsonNull()) { | |||
| @@ -93,7 +93,7 @@ public class WxCpMessageGsonAdapter implements JsonSerializer<WxCpMessage> { | |||
| JsonObject newsJsonObject = new JsonObject(); | |||
| if (message.getMediaId() != null) { | |||
| newsJsonObject.addProperty("media_id", message.getMediaId()); | |||
| }else { | |||
| } else { | |||
| JsonArray articleJsonArray = new JsonArray(); | |||
| for (MpnewsArticle article : message.getMpnewsArticles()) { | |||
| JsonObject articleJson = new JsonObject(); | |||
| @@ -29,7 +29,7 @@ public class WxCpTagGsonAdapter implements JsonSerializer<WxCpTag>, JsonDeserial | |||
| @Override | |||
| public WxCpTag deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) | |||
| throws JsonParseException { | |||
| throws JsonParseException { | |||
| JsonObject jsonObject = json.getAsJsonObject(); | |||
| return new WxCpTag(GsonHelper.getString(jsonObject, "tagid"), GsonHelper.getString(jsonObject, "tagname")); | |||
| } | |||
| @@ -21,7 +21,7 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri | |||
| @Override | |||
| public WxCpUser deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) | |||
| throws JsonParseException { | |||
| throws JsonParseException { | |||
| JsonObject o = json.getAsJsonObject(); | |||
| WxCpUser user = new WxCpUser(); | |||
| user.setUserId(GsonHelper.getString(o, "userid")); | |||
| @@ -50,8 +50,8 @@ public class WxCpUserGsonAdapter implements JsonDeserializer<WxCpUser>, JsonSeri | |||
| JsonArray attrJsonElements = o.get("extattr").getAsJsonObject().get("attrs").getAsJsonArray(); | |||
| for (JsonElement attrJsonElement : attrJsonElements) { | |||
| WxCpUser.Attr attr = new WxCpUser.Attr( | |||
| GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"), | |||
| GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value") | |||
| GsonHelper.getString(attrJsonElement.getAsJsonObject(), "name"), | |||
| GsonHelper.getString(attrJsonElement.getAsJsonObject(), "value") | |||
| ); | |||
| user.getExtAttrs().add(attr); | |||
| } | |||
| @@ -1,16 +1,15 @@ | |||
| package me.chanjar.weixin.cp.api; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import com.google.inject.Binder; | |||
| import com.google.inject.Module; | |||
| import com.thoughtworks.xstream.XStream; | |||
| import com.thoughtworks.xstream.annotations.XStreamAlias; | |||
| import me.chanjar.weixin.common.util.xml.XStreamInitializer; | |||
| import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| public class ApiTestModule implements Module { | |||
| public static <T> T fromXml(Class<T> clazz, InputStream is) { | |||
| @@ -23,9 +22,9 @@ public class ApiTestModule implements Module { | |||
| @Override | |||
| public void configure(Binder binder) { | |||
| try (InputStream is1 = ClassLoader | |||
| .getSystemResourceAsStream("test-config.xml")) { | |||
| .getSystemResourceAsStream("test-config.xml")) { | |||
| WxXmlCpInMemoryConfigStorage config = fromXml( | |||
| WxXmlCpInMemoryConfigStorage.class, is1); | |||
| WxXmlCpInMemoryConfigStorage.class, is1); | |||
| WxCpServiceImpl wxService = new WxCpServiceImpl(); | |||
| wxService.setWxCpConfigStorage(config); | |||
| @@ -72,10 +71,10 @@ public class ApiTestModule implements Module { | |||
| @Override | |||
| public String toString() { | |||
| return super.toString() + " > WxXmlCpConfigStorage{" + | |||
| "userId='" + this.userId + '\'' + | |||
| ", departmentId='" + this.departmentId + '\'' + | |||
| ", tagId='" + this.tagId + '\'' + | |||
| '}'; | |||
| "userId='" + this.userId + '\'' + | |||
| ", departmentId='" + this.departmentId + '\'' + | |||
| ", tagId='" + this.tagId + '\'' + | |||
| '}'; | |||
| } | |||
| } | |||
| @@ -1,16 +1,13 @@ | |||
| package me.chanjar.weixin.cp.api; | |||
| import java.util.List; | |||
| import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Guice; | |||
| import org.testng.annotations.Test; | |||
| import com.google.inject.Inject; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import me.chanjar.weixin.cp.bean.WxCpDepart; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| import java.util.List; | |||
| /** | |||
| * 测试部门接口 | |||
| @@ -1,21 +1,17 @@ | |||
| package me.chanjar.weixin.cp.api; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.DataProvider; | |||
| import org.testng.annotations.Guice; | |||
| import org.testng.annotations.Test; | |||
| import com.google.inject.Inject; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| import me.chanjar.weixin.common.bean.result.WxMediaUploadResult; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| /** | |||
| * 测试多媒体文件上传下载 | |||
| @@ -35,13 +31,13 @@ public class WxCpMediaAPITest { | |||
| @Test(dataProvider = "uploadMedia") | |||
| public void testUploadMedia(String mediaType, String fileType, String fileName) throws WxErrorException, IOException { | |||
| try (InputStream inputStream = ClassLoader | |||
| .getSystemResourceAsStream(fileName);) { | |||
| .getSystemResourceAsStream(fileName);) { | |||
| WxMediaUploadResult res = this.wxService.mediaUpload(mediaType, fileType, | |||
| inputStream); | |||
| inputStream); | |||
| Assert.assertNotNull(res.getType()); | |||
| Assert.assertNotNull(res.getCreatedAt()); | |||
| Assert.assertTrue( | |||
| res.getMediaId() != null || res.getThumbMediaId() != null); | |||
| res.getMediaId() != null || res.getThumbMediaId() != null); | |||
| if (res.getMediaId() != null) { | |||
| this.media_ids.add(res.getMediaId()); | |||
| @@ -55,10 +51,10 @@ public class WxCpMediaAPITest { | |||
| @DataProvider | |||
| public Object[][] uploadMedia() { | |||
| return new Object[][]{ | |||
| new Object[]{WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, | |||
| new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_MP3, "mm.mp3"}, | |||
| new Object[]{WxConsts.MEDIA_VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, | |||
| new Object[]{WxConsts.MEDIA_FILE, TestConstants.FILE_JPG, "mm.jpeg"} | |||
| new Object[]{WxConsts.MEDIA_IMAGE, TestConstants.FILE_JPG, "mm.jpeg"}, | |||
| new Object[]{WxConsts.MEDIA_VOICE, TestConstants.FILE_MP3, "mm.mp3"}, | |||
| new Object[]{WxConsts.MEDIA_VIDEO, TestConstants.FILE_MP4, "mm.mp4"}, | |||
| new Object[]{WxConsts.MEDIA_FILE, TestConstants.FILE_JPG, "mm.jpeg"} | |||
| }; | |||
| } | |||
| @@ -5,9 +5,8 @@ import me.chanjar.weixin.common.session.StandardSessionManager; | |||
| import me.chanjar.weixin.common.session.WxSessionManager; | |||
| import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | |||
| import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.DataProvider; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| import java.util.Map; | |||
| @@ -22,33 +21,33 @@ public class WxCpMessageRouterTest { | |||
| @Test(enabled = false) | |||
| public void prepare(boolean async, StringBuffer sb, WxCpMessageRouter router) { | |||
| router | |||
| .rule() | |||
| .async(async) | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") | |||
| .handler(new WxEchoCpMessageHandler(sb, "COMBINE_4")) | |||
| .end() | |||
| .rule() | |||
| .async(async) | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1") | |||
| .handler(new WxEchoCpMessageHandler(sb, "COMBINE_3")) | |||
| .end() | |||
| .rule() | |||
| .async(async) | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK) | |||
| .handler(new WxEchoCpMessageHandler(sb, "COMBINE_2")) | |||
| .end() | |||
| .rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoCpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() | |||
| .rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoCpMessageHandler(sb, WxConsts.EVT_CLICK)).end() | |||
| .rule().async(async).eventKey("KEY_1").handler(new WxEchoCpMessageHandler(sb, "KEY_1")).end() | |||
| .rule().async(async).content("CONTENT_1").handler(new WxEchoCpMessageHandler(sb, "CONTENT_1")).end() | |||
| .rule().async(async).rContent(".*bc.*").handler(new WxEchoCpMessageHandler(sb, "abcd")).end() | |||
| .rule().async(async).matcher(new WxCpMessageMatcher() { | |||
| .rule() | |||
| .async(async) | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1").content("CONTENT_1") | |||
| .handler(new WxEchoCpMessageHandler(sb, "COMBINE_4")) | |||
| .end() | |||
| .rule() | |||
| .async(async) | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK).eventKey("KEY_1") | |||
| .handler(new WxEchoCpMessageHandler(sb, "COMBINE_3")) | |||
| .end() | |||
| .rule() | |||
| .async(async) | |||
| .msgType(WxConsts.XML_MSG_TEXT).event(WxConsts.EVT_CLICK) | |||
| .handler(new WxEchoCpMessageHandler(sb, "COMBINE_2")) | |||
| .end() | |||
| .rule().async(async).msgType(WxConsts.XML_MSG_TEXT).handler(new WxEchoCpMessageHandler(sb, WxConsts.XML_MSG_TEXT)).end() | |||
| .rule().async(async).event(WxConsts.EVT_CLICK).handler(new WxEchoCpMessageHandler(sb, WxConsts.EVT_CLICK)).end() | |||
| .rule().async(async).eventKey("KEY_1").handler(new WxEchoCpMessageHandler(sb, "KEY_1")).end() | |||
| .rule().async(async).content("CONTENT_1").handler(new WxEchoCpMessageHandler(sb, "CONTENT_1")).end() | |||
| .rule().async(async).rContent(".*bc.*").handler(new WxEchoCpMessageHandler(sb, "abcd")).end() | |||
| .rule().async(async).matcher(new WxCpMessageMatcher() { | |||
| @Override | |||
| public boolean match(WxCpXmlMessage message) { | |||
| return "strangeformat".equals(message.getFormat()); | |||
| } | |||
| }).handler(new WxEchoCpMessageHandler(sb, "matcher")).end() | |||
| .rule().async(async).handler(new WxEchoCpMessageHandler(sb, "ALL")).end(); | |||
| .rule().async(async).handler(new WxEchoCpMessageHandler(sb, "ALL")).end(); | |||
| } | |||
| @Test(dataProvider = "messages-1") | |||
| @@ -138,16 +137,16 @@ public class WxCpMessageRouterTest { | |||
| return new Object[][]{ | |||
| new Object[]{message1, WxConsts.XML_MSG_TEXT + ","}, | |||
| new Object[]{message2, WxConsts.EVT_CLICK + ","}, | |||
| new Object[]{message3, "KEY_1,"}, | |||
| new Object[]{message4, "CONTENT_1,"}, | |||
| new Object[]{message5, "ALL,"}, | |||
| new Object[]{message6, "abcd,"}, | |||
| new Object[]{message7, "matcher,"}, | |||
| new Object[]{c2, "COMBINE_2,"}, | |||
| new Object[]{c3, "COMBINE_3,"}, | |||
| new Object[]{c4, "COMBINE_4,"} | |||
| new Object[]{message1, WxConsts.XML_MSG_TEXT + ","}, | |||
| new Object[]{message2, WxConsts.EVT_CLICK + ","}, | |||
| new Object[]{message3, "KEY_1,"}, | |||
| new Object[]{message4, "CONTENT_1,"}, | |||
| new Object[]{message5, "ALL,"}, | |||
| new Object[]{message6, "abcd,"}, | |||
| new Object[]{message7, "matcher,"}, | |||
| new Object[]{c2, "COMBINE_2,"}, | |||
| new Object[]{c3, "COMBINE_3,"}, | |||
| new Object[]{c4, "COMBINE_4,"} | |||
| }; | |||
| } | |||
| @@ -162,7 +161,7 @@ public class WxCpMessageRouterTest { | |||
| ism.setBackgroundProcessorDelay(1); | |||
| return new Object[][]{ | |||
| new Object[]{ism} | |||
| new Object[]{ism} | |||
| }; | |||
| } | |||
| @@ -174,8 +173,8 @@ public class WxCpMessageRouterTest { | |||
| final WxCpMessageRouter router = new WxCpMessageRouter(null); | |||
| router.setSessionManager(ism); | |||
| router | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).next() | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).end(); | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).next() | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).end(); | |||
| WxCpXmlMessage msg = new WxCpXmlMessage(); | |||
| msg.setFromUserName("abc"); | |||
| @@ -194,8 +193,8 @@ public class WxCpMessageRouterTest { | |||
| final WxCpMessageRouter router = new WxCpMessageRouter(null); | |||
| router.setSessionManager(ism); | |||
| router | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).next() | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).end(); | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).next() | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).end(); | |||
| WxCpXmlMessage msg = new WxCpXmlMessage(); | |||
| msg.setFromUserName("abc"); | |||
| @@ -208,8 +207,8 @@ public class WxCpMessageRouterTest { | |||
| final WxCpMessageRouter router = new WxCpMessageRouter(null); | |||
| router.setSessionManager(ism); | |||
| router | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).next() | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).end(); | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).next() | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).end(); | |||
| WxCpXmlMessage msg = new WxCpXmlMessage(); | |||
| msg.setFromUserName("abc"); | |||
| @@ -228,8 +227,8 @@ public class WxCpMessageRouterTest { | |||
| final WxCpMessageRouter router = new WxCpMessageRouter(null); | |||
| router.setSessionManager(ism); | |||
| router | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).next() | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).end(); | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).next() | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).end(); | |||
| WxCpXmlMessage msg = new WxCpXmlMessage(); | |||
| msg.setFromUserName("abc"); | |||
| @@ -248,7 +247,7 @@ public class WxCpMessageRouterTest { | |||
| final WxCpMessageRouter router = new WxCpMessageRouter(null); | |||
| router.setSessionManager(ism); | |||
| router | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).end(); | |||
| .rule().async(false).handler(new WxSessionMessageHandler()).end(); | |||
| WxCpXmlMessage msg = new WxCpXmlMessage(); | |||
| msg.setFromUserName("abc"); | |||
| @@ -262,7 +261,7 @@ public class WxCpMessageRouterTest { | |||
| final WxCpMessageRouter router = new WxCpMessageRouter(null); | |||
| router.setSessionManager(ism); | |||
| router | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).end(); | |||
| .rule().async(true).handler(new WxSessionMessageHandler()).end(); | |||
| WxCpXmlMessage msg = new WxCpXmlMessage(); | |||
| msg.setFromUserName("abc"); | |||
| @@ -4,9 +4,8 @@ import com.google.inject.Inject; | |||
| import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import me.chanjar.weixin.cp.bean.WxCpTag; | |||
| import me.chanjar.weixin.cp.bean.WxCpUser; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Guice; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| import java.util.ArrayList; | |||
| import java.util.List; | |||
| @@ -5,9 +5,8 @@ import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import me.chanjar.weixin.cp.bean.WxCpDepart; | |||
| import me.chanjar.weixin.cp.bean.WxCpUser; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Guice; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| import java.util.List; | |||
| @@ -6,10 +6,8 @@ import me.chanjar.weixin.common.bean.menu.WxMenu; | |||
| import me.chanjar.weixin.common.bean.menu.WxMenuButton; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.DataProvider; | |||
| import org.testng.annotations.Guice; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| /** | |||
| * 测试菜单 | |||
| @@ -78,9 +76,9 @@ public class WxMenuAPITest { | |||
| button3.getSubButtons().add(button33); | |||
| return new Object[][]{ | |||
| new Object[]{ | |||
| menu | |||
| } | |||
| new Object[]{ | |||
| menu | |||
| } | |||
| }; | |||
| } | |||
| @@ -5,9 +5,8 @@ import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.cp.api.ApiTestModule; | |||
| import me.chanjar.weixin.cp.api.WxCpConfigStorage; | |||
| import org.apache.commons.lang3.StringUtils; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Guice; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| /** | |||
| * 基础API测试 | |||
| @@ -4,8 +4,7 @@ import me.chanjar.weixin.common.bean.result.WxError; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.common.util.http.RequestExecutor; | |||
| import me.chanjar.weixin.cp.api.WxCpService; | |||
| import org.testng.annotations.DataProvider; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.annotations.*; | |||
| import java.util.concurrent.ExecutionException; | |||
| import java.util.concurrent.ExecutorService; | |||
| @@ -22,7 +21,7 @@ public class WxCpBusyRetryTest { | |||
| @Override | |||
| public synchronized <T, E> T executeInternal( | |||
| RequestExecutor<T, E> executor, String uri, E data) | |||
| throws WxErrorException { | |||
| throws WxErrorException { | |||
| this.log.info("Executed"); | |||
| WxError error = new WxError(); | |||
| error.setErrorCode(-1); | |||
| @@ -33,7 +32,7 @@ public class WxCpBusyRetryTest { | |||
| service.setMaxRetryTimes(3); | |||
| service.setRetrySleepMillis(500); | |||
| return new Object[][]{ | |||
| new Object[]{service} | |||
| new Object[]{service} | |||
| }; | |||
| } | |||
| @@ -5,8 +5,7 @@ import me.chanjar.weixin.common.api.WxConsts; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.cp.api.ApiTestModule; | |||
| import me.chanjar.weixin.cp.bean.WxCpMessage; | |||
| import org.testng.annotations.Guice; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.annotations.*; | |||
| /*** | |||
| * 测试发送消息 | |||
| @@ -30,11 +29,11 @@ public class WxCpMessageAPITest { | |||
| this.wxService.messageSend(message1); | |||
| WxCpMessage message2 = WxCpMessage | |||
| .TEXT() | |||
| .agentId(configStorage.getAgentId()) | |||
| .toUser(configStorage.getUserId()) | |||
| .content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>") | |||
| .build(); | |||
| .TEXT() | |||
| .agentId(configStorage.getAgentId()) | |||
| .toUser(configStorage.getUserId()) | |||
| .content("欢迎欢迎,热烈欢迎\n换行测试\n超链接:<a href=\"http://www.baidu.com\">Hello World</a>") | |||
| .build(); | |||
| this.wxService.messageSend(message2); | |||
| } | |||
| @@ -1,12 +1,11 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| import me.chanjar.weixin.cp.bean.article.NewArticle; | |||
| import me.chanjar.weixin.cp.bean.article.MpnewsArticle; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import me.chanjar.weixin.cp.bean.article.NewArticle; | |||
| import org.testng.annotations.*; | |||
| import static org.testng.Assert.assertEquals; | |||
| import static org.testng.Assert.*; | |||
| @Test | |||
| public class WxCpMessageTest { | |||
| @@ -1,8 +1,8 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import me.chanjar.weixin.common.api.WxConsts; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxCpXmlMessageTest { | |||
| @@ -10,49 +10,49 @@ public class WxCpXmlMessageTest { | |||
| public void testFromXml() { | |||
| String xml = "<xml>" | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName> " | |||
| + "<CreateTime>1348831860</CreateTime>" | |||
| + "<MsgType><![CDATA[text]]></MsgType>" | |||
| + "<Content><![CDATA[this is a test]]></Content>" | |||
| + "<MsgId>1234567890123456</MsgId>" | |||
| + "<PicUrl><![CDATA[this is a url]]></PicUrl>" | |||
| + "<MediaId><![CDATA[media_id]]></MediaId>" | |||
| + "<Format><![CDATA[Format]]></Format>" | |||
| + "<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>" | |||
| + "<Location_X>23.134521</Location_X>" | |||
| + "<Location_Y>113.358803</Location_Y>" | |||
| + "<Scale>20</Scale>" | |||
| + "<Label><![CDATA[位置信息]]></Label>" | |||
| + "<Description><![CDATA[公众平台官网链接]]></Description>" | |||
| + "<Url><![CDATA[url]]></Url>" | |||
| + "<Title><![CDATA[公众平台官网链接]]></Title>" | |||
| + "<Event><![CDATA[subscribe]]></Event>" | |||
| + "<EventKey><![CDATA[qrscene_123123]]></EventKey>" | |||
| + "<Ticket><![CDATA[TICKET]]></Ticket>" | |||
| + "<Latitude>23.137466</Latitude>" | |||
| + "<Longitude>113.352425</Longitude>" | |||
| + "<Precision>119.385040</Precision>" | |||
| + "<ScanCodeInfo>" | |||
| + " <ScanType><![CDATA[qrcode]]></ScanType>" | |||
| + " <ScanResult><![CDATA[1]]></ScanResult>" | |||
| + "</ScanCodeInfo>" | |||
| + "<SendPicsInfo>" | |||
| + " <Count>1</Count>\n" | |||
| + " <PicList>" | |||
| + " <item>" | |||
| + " <PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>" | |||
| + " </item>" | |||
| + " </PicList>" | |||
| + "</SendPicsInfo>" | |||
| + "<SendLocationInfo>" | |||
| + " <Location_X><![CDATA[23]]></Location_X>\n" | |||
| + " <Location_Y><![CDATA[113]]></Location_Y>\n" | |||
| + " <Scale><![CDATA[15]]></Scale>\n" | |||
| + " <Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>\n" | |||
| + " <Poiname><![CDATA[wo de poi]]></Poiname>\n" | |||
| + "</SendLocationInfo>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName> " | |||
| + "<CreateTime>1348831860</CreateTime>" | |||
| + "<MsgType><![CDATA[text]]></MsgType>" | |||
| + "<Content><![CDATA[this is a test]]></Content>" | |||
| + "<MsgId>1234567890123456</MsgId>" | |||
| + "<PicUrl><![CDATA[this is a url]]></PicUrl>" | |||
| + "<MediaId><![CDATA[media_id]]></MediaId>" | |||
| + "<Format><![CDATA[Format]]></Format>" | |||
| + "<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>" | |||
| + "<Location_X>23.134521</Location_X>" | |||
| + "<Location_Y>113.358803</Location_Y>" | |||
| + "<Scale>20</Scale>" | |||
| + "<Label><![CDATA[位置信息]]></Label>" | |||
| + "<Description><![CDATA[公众平台官网链接]]></Description>" | |||
| + "<Url><![CDATA[url]]></Url>" | |||
| + "<Title><![CDATA[公众平台官网链接]]></Title>" | |||
| + "<Event><![CDATA[subscribe]]></Event>" | |||
| + "<EventKey><![CDATA[qrscene_123123]]></EventKey>" | |||
| + "<Ticket><![CDATA[TICKET]]></Ticket>" | |||
| + "<Latitude>23.137466</Latitude>" | |||
| + "<Longitude>113.352425</Longitude>" | |||
| + "<Precision>119.385040</Precision>" | |||
| + "<ScanCodeInfo>" | |||
| + " <ScanType><![CDATA[qrcode]]></ScanType>" | |||
| + " <ScanResult><![CDATA[1]]></ScanResult>" | |||
| + "</ScanCodeInfo>" | |||
| + "<SendPicsInfo>" | |||
| + " <Count>1</Count>\n" | |||
| + " <PicList>" | |||
| + " <item>" | |||
| + " <PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>" | |||
| + " </item>" | |||
| + " </PicList>" | |||
| + "</SendPicsInfo>" | |||
| + "<SendLocationInfo>" | |||
| + " <Location_X><![CDATA[23]]></Location_X>\n" | |||
| + " <Location_Y><![CDATA[113]]></Location_Y>\n" | |||
| + " <Scale><![CDATA[15]]></Scale>\n" | |||
| + " <Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>\n" | |||
| + " <Poiname><![CDATA[wo de poi]]></Poiname>\n" | |||
| + "</SendLocationInfo>" | |||
| + "</xml>"; | |||
| WxCpXmlMessage wxMessage = WxCpXmlMessage.fromXml(xml); | |||
| Assert.assertEquals(wxMessage.getToUserName(), "toUser"); | |||
| Assert.assertEquals(wxMessage.getFromUserName(), "fromUser"); | |||
| @@ -1,7 +1,7 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxCpXmlOutImageMessageTest { | |||
| @@ -14,12 +14,12 @@ public class WxCpXmlOutImageMessageTest { | |||
| m.setToUserName("to"); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[image]]></MsgType>" | |||
| + "<Image><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Image>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[image]]></MsgType>" | |||
| + "<Image><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Image>" | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); | |||
| } | |||
| @@ -27,21 +27,21 @@ public class WxCpXmlOutImageMessageTest { | |||
| public void testBuild() { | |||
| WxCpXmlOutImageMessage m = WxCpXmlOutMessage.IMAGE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[image]]></MsgType>" | |||
| + "<Image><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Image>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[image]]></MsgType>" | |||
| + "<Image><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Image>" | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals( | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| ); | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxCpXmlOutNewsMessageTest { | |||
| @@ -21,26 +21,26 @@ public class WxCpXmlOutNewsMessageTest { | |||
| m.addArticle(item); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[news]]></MsgType>" | |||
| + " <Articles>" | |||
| + " <item>" | |||
| + " <Title><![CDATA[title]]></Title>" | |||
| + " <Description><![CDATA[description]]></Description>" | |||
| + " <PicUrl><![CDATA[picUrl]]></PicUrl>" | |||
| + " <Url><![CDATA[url]]></Url>" | |||
| + " </item>" | |||
| + " <item>" | |||
| + " <Title><![CDATA[title]]></Title>" | |||
| + " <Description><![CDATA[description]]></Description>" | |||
| + " <PicUrl><![CDATA[picUrl]]></PicUrl>" | |||
| + " <Url><![CDATA[url]]></Url>" | |||
| + " </item>" | |||
| + " </Articles>" | |||
| + " <ArticleCount>2</ArticleCount>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[news]]></MsgType>" | |||
| + " <Articles>" | |||
| + " <item>" | |||
| + " <Title><![CDATA[title]]></Title>" | |||
| + " <Description><![CDATA[description]]></Description>" | |||
| + " <PicUrl><![CDATA[picUrl]]></PicUrl>" | |||
| + " <Url><![CDATA[url]]></Url>" | |||
| + " </item>" | |||
| + " <item>" | |||
| + " <Title><![CDATA[title]]></Title>" | |||
| + " <Description><![CDATA[description]]></Description>" | |||
| + " <PicUrl><![CDATA[picUrl]]></PicUrl>" | |||
| + " <Url><![CDATA[url]]></Url>" | |||
| + " </item>" | |||
| + " </Articles>" | |||
| + " <ArticleCount>2</ArticleCount>" | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); | |||
| } | |||
| @@ -53,41 +53,41 @@ public class WxCpXmlOutNewsMessageTest { | |||
| item.setUrl("url"); | |||
| WxCpXmlOutNewsMessage m = WxCpXmlOutMessage.NEWS() | |||
| .fromUser("fromUser") | |||
| .toUser("toUser") | |||
| .addArticle(item) | |||
| .addArticle(item) | |||
| .build(); | |||
| .fromUser("fromUser") | |||
| .toUser("toUser") | |||
| .addArticle(item) | |||
| .addArticle(item) | |||
| .build(); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[news]]></MsgType>" | |||
| + " <Articles>" | |||
| + " <item>" | |||
| + " <Title><![CDATA[title]]></Title>" | |||
| + " <Description><![CDATA[description]]></Description>" | |||
| + " <PicUrl><![CDATA[picUrl]]></PicUrl>" | |||
| + " <Url><![CDATA[url]]></Url>" | |||
| + " </item>" | |||
| + " <item>" | |||
| + " <Title><![CDATA[title]]></Title>" | |||
| + " <Description><![CDATA[description]]></Description>" | |||
| + " <PicUrl><![CDATA[picUrl]]></PicUrl>" | |||
| + " <Url><![CDATA[url]]></Url>" | |||
| + " </item>" | |||
| + " </Articles>" | |||
| + " <ArticleCount>2</ArticleCount>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[news]]></MsgType>" | |||
| + " <Articles>" | |||
| + " <item>" | |||
| + " <Title><![CDATA[title]]></Title>" | |||
| + " <Description><![CDATA[description]]></Description>" | |||
| + " <PicUrl><![CDATA[picUrl]]></PicUrl>" | |||
| + " <Url><![CDATA[url]]></Url>" | |||
| + " </item>" | |||
| + " <item>" | |||
| + " <Title><![CDATA[title]]></Title>" | |||
| + " <Description><![CDATA[description]]></Description>" | |||
| + " <PicUrl><![CDATA[picUrl]]></PicUrl>" | |||
| + " <Url><![CDATA[url]]></Url>" | |||
| + " </item>" | |||
| + " </Articles>" | |||
| + " <ArticleCount>2</ArticleCount>" | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals( | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| ); | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxCpXmlOutTextMessageTest { | |||
| @@ -14,12 +14,12 @@ public class WxCpXmlOutTextMessageTest { | |||
| m.setToUserName("to"); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[text]]></MsgType>" | |||
| + "<Content><![CDATA[content]]></Content>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[text]]></MsgType>" | |||
| + "<Content><![CDATA[content]]></Content>" | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); | |||
| } | |||
| @@ -27,21 +27,21 @@ public class WxCpXmlOutTextMessageTest { | |||
| public void testBuild() { | |||
| WxCpXmlOutTextMessage m = WxCpXmlOutMessage.TEXT().content("content").fromUser("from").toUser("to").build(); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[text]]></MsgType>" | |||
| + "<Content><![CDATA[content]]></Content>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[text]]></MsgType>" | |||
| + "<Content><![CDATA[content]]></Content>" | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals( | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| ); | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxCpXmlOutVideoMessageTest { | |||
| @@ -16,48 +16,48 @@ public class WxCpXmlOutVideoMessageTest { | |||
| m.setToUserName("toUser"); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[video]]></MsgType>" | |||
| + "<Video>" | |||
| + "<MediaId><![CDATA[media_id]]></MediaId>" | |||
| + "<Title><![CDATA[title]]></Title>" | |||
| + "<Description><![CDATA[ddfff]]></Description>" | |||
| + "</Video> " | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[video]]></MsgType>" | |||
| + "<Video>" | |||
| + "<MediaId><![CDATA[media_id]]></MediaId>" | |||
| + "<Title><![CDATA[title]]></Title>" | |||
| + "<Description><![CDATA[ddfff]]></Description>" | |||
| + "</Video> " | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); | |||
| } | |||
| public void testBuild() { | |||
| WxCpXmlOutVideoMessage m = WxCpXmlOutMessage.VIDEO() | |||
| .mediaId("media_id") | |||
| .fromUser("fromUser") | |||
| .toUser("toUser") | |||
| .title("title") | |||
| .description("ddfff") | |||
| .build(); | |||
| .mediaId("media_id") | |||
| .fromUser("fromUser") | |||
| .toUser("toUser") | |||
| .title("title") | |||
| .description("ddfff") | |||
| .build(); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[video]]></MsgType>" | |||
| + "<Video>" | |||
| + "<MediaId><![CDATA[media_id]]></MediaId>" | |||
| + "<Title><![CDATA[title]]></Title>" | |||
| + "<Description><![CDATA[ddfff]]></Description>" | |||
| + "</Video> " | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[toUser]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[fromUser]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[video]]></MsgType>" | |||
| + "<Video>" | |||
| + "<MediaId><![CDATA[media_id]]></MediaId>" | |||
| + "<Title><![CDATA[title]]></Title>" | |||
| + "<Description><![CDATA[ddfff]]></Description>" | |||
| + "</Video> " | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals( | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| ); | |||
| } | |||
| @@ -1,7 +1,7 @@ | |||
| package me.chanjar.weixin.cp.bean; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Test; | |||
| import org.testng.*; | |||
| import org.testng.annotations.*; | |||
| @Test | |||
| public class WxCpXmlOutVoiceMessageTest { | |||
| @@ -14,12 +14,12 @@ public class WxCpXmlOutVoiceMessageTest { | |||
| m.setToUserName("to"); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[voice]]></MsgType>" | |||
| + "<Voice><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Voice>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[voice]]></MsgType>" | |||
| + "<Voice><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Voice>" | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals(m.toXml().replaceAll("\\s", ""), expected.replaceAll("\\s", "")); | |||
| } | |||
| @@ -27,21 +27,21 @@ public class WxCpXmlOutVoiceMessageTest { | |||
| public void testBuild() { | |||
| WxCpXmlOutVoiceMessage m = WxCpXmlOutMessage.VOICE().mediaId("ddfefesfsdfef").fromUser("from").toUser("to").build(); | |||
| String expected = "<xml>" | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[voice]]></MsgType>" | |||
| + "<Voice><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Voice>" | |||
| + "</xml>"; | |||
| + "<ToUserName><![CDATA[to]]></ToUserName>" | |||
| + "<FromUserName><![CDATA[from]]></FromUserName>" | |||
| + "<CreateTime>1122</CreateTime>" | |||
| + "<MsgType><![CDATA[voice]]></MsgType>" | |||
| + "<Voice><MediaId><![CDATA[ddfefesfsdfef]]></MediaId></Voice>" | |||
| + "</xml>"; | |||
| System.out.println(m.toXml()); | |||
| Assert.assertEquals( | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| m | |||
| .toXml() | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", ""), | |||
| expected | |||
| .replaceAll("\\s", "") | |||
| .replaceAll("<CreateTime>.*?</CreateTime>", "") | |||
| ); | |||
| } | |||
| @@ -22,7 +22,7 @@ class WxCpDemoInMemoryConfigStorage extends WxCpInMemoryConfigStorage { | |||
| @Override | |||
| public String toString() { | |||
| return "SimpleWxConfigProvider [appidOrCorpid=" + this.corpId + ", corpSecret=" + this.corpSecret + ", accessToken=" + this.accessToken | |||
| + ", expiresTime=" + this.expiresTime + ", token=" + this.token + ", aesKey=" + this.aesKey + "]"; | |||
| + ", expiresTime=" + this.expiresTime + ", token=" + this.token + ", aesKey=" + this.aesKey + "]"; | |||
| } | |||
| } | |||
| @@ -1,13 +1,5 @@ | |||
| package me.chanjar.weixin.cp.demo; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.Map; | |||
| import org.eclipse.jetty.server.Server; | |||
| import org.eclipse.jetty.servlet.ServletHandler; | |||
| import org.eclipse.jetty.servlet.ServletHolder; | |||
| import me.chanjar.weixin.common.session.WxSessionManager; | |||
| import me.chanjar.weixin.cp.api.WxCpConfigStorage; | |||
| import me.chanjar.weixin.cp.api.WxCpMessageHandler; | |||
| @@ -17,6 +9,13 @@ import me.chanjar.weixin.cp.api.impl.apache.WxCpServiceImpl; | |||
| import me.chanjar.weixin.cp.bean.WxCpXmlMessage; | |||
| import me.chanjar.weixin.cp.bean.WxCpXmlOutMessage; | |||
| import me.chanjar.weixin.cp.bean.WxCpXmlOutTextMessage; | |||
| import org.eclipse.jetty.server.Server; | |||
| import org.eclipse.jetty.servlet.ServletHandler; | |||
| import org.eclipse.jetty.servlet.ServletHolder; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.util.Map; | |||
| public class WxCpDemoServer { | |||
| @@ -44,9 +43,9 @@ public class WxCpDemoServer { | |||
| private static void initWeixin() throws IOException { | |||
| try (InputStream is1 = ClassLoader | |||
| .getSystemResourceAsStream("test-config.xml")) { | |||
| .getSystemResourceAsStream("test-config.xml")) { | |||
| WxCpDemoInMemoryConfigStorage config = WxCpDemoInMemoryConfigStorage | |||
| .fromXml(is1); | |||
| .fromXml(is1); | |||
| wxCpConfigStorage = config; | |||
| wxCpService = new WxCpServiceImpl(); | |||
| @@ -55,11 +54,11 @@ public class WxCpDemoServer { | |||
| WxCpMessageHandler handler = new WxCpMessageHandler() { | |||
| @Override | |||
| public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, | |||
| Map<String, Object> context, WxCpService wxService, | |||
| WxSessionManager sessionManager) { | |||
| Map<String, Object> context, WxCpService wxService, | |||
| WxSessionManager sessionManager) { | |||
| WxCpXmlOutTextMessage m = WxCpXmlOutMessage.TEXT().content("测试加密消息") | |||
| .fromUser(wxMessage.getToUserName()) | |||
| .toUser(wxMessage.getFromUserName()).build(); | |||
| .fromUser(wxMessage.getToUserName()) | |||
| .toUser(wxMessage.getFromUserName()).build(); | |||
| return m; | |||
| } | |||
| }; | |||
| @@ -67,22 +66,22 @@ public class WxCpDemoServer { | |||
| WxCpMessageHandler oauth2handler = new WxCpMessageHandler() { | |||
| @Override | |||
| public WxCpXmlOutMessage handle(WxCpXmlMessage wxMessage, | |||
| Map<String, Object> context, WxCpService wxService, | |||
| WxSessionManager sessionManager) { | |||
| Map<String, Object> context, WxCpService wxService, | |||
| WxSessionManager sessionManager) { | |||
| String href = "<a href=\"" | |||
| + wxService.oauth2buildAuthorizationUrl( | |||
| wxCpConfigStorage.getOauth2redirectUri(), null) | |||
| + "\">测试oauth2</a>"; | |||
| + wxService.oauth2buildAuthorizationUrl( | |||
| wxCpConfigStorage.getOauth2redirectUri(), null) | |||
| + "\">测试oauth2</a>"; | |||
| return WxCpXmlOutMessage.TEXT().content(href) | |||
| .fromUser(wxMessage.getToUserName()) | |||
| .toUser(wxMessage.getFromUserName()).build(); | |||
| .fromUser(wxMessage.getToUserName()) | |||
| .toUser(wxMessage.getFromUserName()).build(); | |||
| } | |||
| }; | |||
| wxCpMessageRouter = new WxCpMessageRouter(wxCpService); | |||
| wxCpMessageRouter.rule().async(false).content("哈哈") // 拦截内容为“哈哈”的消息 | |||
| .handler(handler).end().rule().async(false).content("oauth") | |||
| .handler(oauth2handler).end(); | |||
| .handler(handler).end().rule().async(false).content("oauth") | |||
| .handler(oauth2handler).end(); | |||
| } | |||
| } | |||
| @@ -31,7 +31,7 @@ public class WxCpEndpointServlet extends HttpServlet { | |||
| @Override | |||
| protected void service(HttpServletRequest request, HttpServletResponse response) | |||
| throws IOException { | |||
| throws IOException { | |||
| response.setContentType("text/html;charset=utf-8"); | |||
| response.setStatus(HttpServletResponse.SC_OK); | |||
| @@ -55,7 +55,7 @@ public class WxCpEndpointServlet extends HttpServlet { | |||
| } | |||
| WxCpXmlMessage inMessage = WxCpXmlMessage | |||
| .fromEncryptedXml(request.getInputStream(), this.wxCpConfigStorage, timestamp, nonce, msgSignature); | |||
| .fromEncryptedXml(request.getInputStream(), this.wxCpConfigStorage, timestamp, nonce, msgSignature); | |||
| WxCpXmlOutMessage outMessage = this.wxCpMessageRouter.route(inMessage); | |||
| if (outMessage != null) { | |||
| response.getWriter().write(outMessage.toEncryptedXml(this.wxCpConfigStorage)); | |||
| @@ -1,14 +1,13 @@ | |||
| package me.chanjar.weixin.cp.demo; | |||
| import java.io.IOException; | |||
| import java.util.Arrays; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.cp.api.WxCpService; | |||
| import javax.servlet.http.HttpServlet; | |||
| import javax.servlet.http.HttpServletRequest; | |||
| import javax.servlet.http.HttpServletResponse; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.cp.api.WxCpService; | |||
| import java.io.IOException; | |||
| import java.util.Arrays; | |||
| public class WxCpOAuth2Servlet extends HttpServlet { | |||
| private static final long serialVersionUID = 1L; | |||
| @@ -21,7 +20,7 @@ public class WxCpOAuth2Servlet extends HttpServlet { | |||
| @Override | |||
| protected void service(HttpServletRequest request, HttpServletResponse response) | |||
| throws IOException { | |||
| throws IOException { | |||
| response.setContentType("text/html;charset=utf-8"); | |||
| response.setStatus(HttpServletResponse.SC_OK); | |||
| @@ -9,8 +9,8 @@ | |||
| </appender> | |||
| <root level="info"> | |||
| <appender-ref ref="STDOUT" /> | |||
| <appender-ref ref="STDOUT"/> | |||
| </root> | |||
| <logger name="me.chanjar.weixin.cp" level="debug" /> | |||
| <logger name="me.chanjar.weixin.cp" level="debug"/> | |||
| </configuration> | |||
| @@ -1,13 +1,13 @@ | |||
| <xml> | |||
| <corpId>企业号corpid</corpId> | |||
| <corpSecret>企业号corpsecret</corpSecret> | |||
| <agentId>企业号应用id</agentId> | |||
| <token>企业号应用Token</token> | |||
| <aesKey>企业号应用EncodingAESKey</aesKey> | |||
| <accessToken>可以不填写</accessToken> | |||
| <expiresTime>可以不填写</expiresTime> | |||
| <userId>企业号通讯录里的某个userid</userId> | |||
| <departmentId>企业号通讯录的某个部门id</departmentId> | |||
| <tagId>企业号通讯录里的某个tagid</tagId> | |||
| <oauth2redirectUri>网页授权获取用户信息回调地址</oauth2redirectUri> | |||
| <corpId>企业号corpid</corpId> | |||
| <corpSecret>企业号corpsecret</corpSecret> | |||
| <agentId>企业号应用id</agentId> | |||
| <token>企业号应用Token</token> | |||
| <aesKey>企业号应用EncodingAESKey</aesKey> | |||
| <accessToken>可以不填写</accessToken> | |||
| <expiresTime>可以不填写</expiresTime> | |||
| <userId>企业号通讯录里的某个userid</userId> | |||
| <departmentId>企业号通讯录的某个部门id</departmentId> | |||
| <tagId>企业号通讯录里的某个tagid</tagId> | |||
| <oauth2redirectUri>网页授权获取用户信息回调地址</oauth2redirectUri> | |||
| </xml> | |||
| @@ -1,13 +1,12 @@ | |||
| description = 'WeiXin Java Tools - MP' | |||
| dependencies { | |||
| compile project(':weixin-java-common') | |||
| testCompile group: 'junit', name: 'junit', version:'4.11' | |||
| testCompile group: 'org.testng', name: 'testng', version:'6.8.7' | |||
| testCompile group: 'org.mockito', name: 'mockito-all', version:'1.9.5' | |||
| testCompile group: 'com.google.inject', name: 'guice', version:'3.0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version:'9.3.0.RC0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version:'9.3.0.RC0' | |||
| testCompile group: 'joda-time', name: 'joda-time', version:'2.9.4' | |||
| testCompile group: 'junit', name: 'junit', version: '4.11' | |||
| testCompile group: 'org.testng', name: 'testng', version: '6.8.7' | |||
| testCompile group: 'org.mockito', name: 'mockito-all', version: '1.9.5' | |||
| testCompile group: 'com.google.inject', name: 'guice', version: '3.0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-server', version: '9.3.0.RC0' | |||
| testCompile group: 'org.eclipse.jetty', name: 'jetty-servlet', version: '9.3.0.RC0' | |||
| testCompile group: 'joda-time', name: 'joda-time', version: '2.9.4' | |||
| } | |||
| test.useTestNG() | |||
| @@ -1,7 +1,8 @@ | |||
| <?xml version="1.0"?> | |||
| <project | |||
| 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"> | |||
| 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"> | |||
| <modelVersion>4.0.0</modelVersion> | |||
| <parent> | |||
| <groupId>com.github.binarywang</groupId> | |||
| @@ -6,6 +6,7 @@ import me.chanjar.weixin.mp.bean.result.WxMpCardResult; | |||
| /** | |||
| * 卡券相关接口 | |||
| * | |||
| * @author YuJian(mgcnrx11@hotmail.com) on 01/11/2016 | |||
| */ | |||
| public interface WxMpCardService { | |||
| @@ -52,7 +53,7 @@ public interface WxMpCardService { | |||
| * @return 卡券Api签名对象 | |||
| */ | |||
| WxCardApiSignature createCardApiSignature(String... optionalSignParam) throws | |||
| WxErrorException; | |||
| WxErrorException; | |||
| /** | |||
| * 卡券Code解码 | |||
| @@ -71,7 +72,7 @@ public interface WxMpCardService { | |||
| * @return WxMpCardResult对象 | |||
| */ | |||
| WxMpCardResult queryCardCode(String cardId, String code, boolean checkConsume) | |||
| throws WxErrorException; | |||
| throws WxErrorException; | |||
| /** | |||
| * 卡券Code核销。核销失败会抛出异常 | |||
| @@ -103,7 +104,7 @@ public interface WxMpCardService { | |||
| * @param isMark 是否要mark(占用)这个code,填写true或者false,表示占用或解除占用 | |||
| */ | |||
| void markCardCode(String code, String cardId, String openId, boolean isMark) throws | |||
| WxErrorException; | |||
| WxErrorException; | |||
| /** | |||
| * 查看卡券详情接口 | |||
| @@ -1,19 +1,15 @@ | |||
| package me.chanjar.weixin.mp.api; | |||
| import me.chanjar.weixin.common.exception.WxErrorException; | |||
| import me.chanjar.weixin.mp.bean.datacube.WxDataCubeArticleResult; | |||
| import me.chanjar.weixin.mp.bean.datacube.WxDataCubeArticleTotal; | |||
| import me.chanjar.weixin.mp.bean.datacube.WxDataCubeInterfaceResult; | |||
| import me.chanjar.weixin.mp.bean.datacube.WxDataCubeMsgResult; | |||
| import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserCumulate; | |||
| import me.chanjar.weixin.mp.bean.datacube.WxDataCubeUserSummary; | |||
| import me.chanjar.weixin.mp.bean.datacube.*; | |||
| import java.util.Date; | |||
| import java.util.List; | |||
| /** | |||
| * 统计分析相关接口 | |||
| * Created by Binary Wang on 2016/8/23. | |||
| * Created by Binary Wang on 2016/8/23. | |||
| * | |||
| * @author binarywang (https://github.com/binarywang) | |||
| */ | |||
| public interface WxMpDataCubeService { | |||
| @@ -192,6 +188,7 @@ public interface WxMpDataCubeService { | |||
| List<WxDataCubeMsgResult> getUpstreamMsgDistMonth(Date beginDate, Date endDate) throws WxErrorException; | |||
| //*******************接口分析数据接口***********************// | |||
| /** | |||
| * <pre> | |||
| * 获取接口分析数据(getinterfacesummary) | |||
| @@ -20,6 +20,7 @@ public interface WxMpDeviceService { | |||
| * 获取一组新的deviceid和设备二维码 | |||
| * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-6 | |||
| * </pre> | |||
| * | |||
| * @param productId 产品id | |||
| * @return 返回WxDeviceQrCodeResult | |||
| */ | |||
| @@ -30,6 +31,7 @@ public interface WxMpDeviceService { | |||
| * 将device id及其属性信息提交公众平台进行授权 | |||
| * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-6 | |||
| * </pre> | |||
| * | |||
| * @param wxDeviceAuthorize 授权请求对象 | |||
| * @return WxDeviceAuthorizeResult | |||
| */ | |||
| @@ -41,6 +43,7 @@ public interface WxMpDeviceService { | |||
| * 第三方后台绑定成功后,通知公众平台 | |||
| * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html/page=3-4-7 | |||
| * </pre> | |||
| * | |||
| * @param wxDeviceBind 绑定请求对象 | |||
| * @return WxDeviceBindResult | |||
| */ | |||
| @@ -51,6 +54,7 @@ public interface WxMpDeviceService { | |||
| * 强制绑定用户和设备 | |||
| * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-7 | |||
| * </pre> | |||
| * | |||
| * @param wxDeviceBind 强制绑定请求对象 | |||
| * @return WxDeviceBindResult | |||
| */ | |||
| @@ -61,6 +65,7 @@ public interface WxMpDeviceService { | |||
| * 第三方确认用户和设备的解绑操作 | |||
| * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html/page=3-4-7 | |||
| * </pre> | |||
| * | |||
| * @param wxDeviceBind 绑定请求对象 | |||
| * @return WxDeviceBidResult | |||
| */ | |||
| @@ -71,6 +76,7 @@ public interface WxMpDeviceService { | |||
| * 强制解绑用户和设备 | |||
| * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-7 | |||
| * </pre> | |||
| * | |||
| * @param wxDeviceBind 强制解绑请求对象 | |||
| * @return WxDeviceBindResult | |||
| */ | |||
| @@ -81,17 +87,19 @@ public interface WxMpDeviceService { | |||
| * 通过device type和device id 获取设备主人的openid | |||
| * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-11 | |||
| * </pre> | |||
| * | |||
| * @param deviceType 设备类型,目前为"公众账号原始ID" | |||
| * @param deviceId 设备ID | |||
| * @param deviceId 设备ID | |||
| * @return WxDeviceOpenIdResult | |||
| */ | |||
| WxDeviceOpenIdResult getOpenId(String deviceType,String deviceId) throws WxErrorException; | |||
| WxDeviceOpenIdResult getOpenId(String deviceType, String deviceId) throws WxErrorException; | |||
| /** | |||
| * <pre> | |||
| * 通过openid获取用户在当前devicetype下绑定的deviceid列表` | |||
| * 详情请见:http://iot.weixin.qq.com/wiki/new/index.html?page=3-4-12 | |||
| * </pre> | |||
| * | |||
| * @param openId 要查询的用户的openid | |||
| * @return WxDeviceBindDeviceResult | |||
| */ | |||
| @@ -51,6 +51,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
| return this.accessToken; | |||
| } | |||
| public void setAccessToken(String accessToken) { | |||
| this.accessToken = accessToken; | |||
| } | |||
| @Override | |||
| public Lock getAccessTokenLock() { | |||
| return this.accessTokenLock; | |||
| @@ -82,6 +86,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
| return this.jsapiTicket; | |||
| } | |||
| public void setJsapiTicket(String jsapiTicket) { | |||
| this.jsapiTicket = jsapiTicket; | |||
| } | |||
| @Override | |||
| public Lock getJsapiTicketLock() { | |||
| return this.jsapiTicketLock; | |||
| @@ -112,6 +120,10 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
| return this.cardApiTicket; | |||
| } | |||
| public void setCardApiTicket(String cardApiTicket) { | |||
| this.cardApiTicket = cardApiTicket; | |||
| } | |||
| @Override | |||
| public Lock getCardApiTicketLock() { | |||
| return this.cardApiTicketLock; | |||
| @@ -247,14 +259,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
| this.apacheHttpClientBuilder = apacheHttpClientBuilder; | |||
| } | |||
| public void setAccessToken(String accessToken) { | |||
| this.accessToken = accessToken; | |||
| } | |||
| public void setJsapiTicket(String jsapiTicket) { | |||
| this.jsapiTicket = jsapiTicket; | |||
| } | |||
| public long getJsapiTicketExpiresTime() { | |||
| return this.jsapiTicketExpiresTime; | |||
| } | |||
| @@ -263,10 +267,6 @@ public class WxMpInMemoryConfigStorage implements WxMpConfigStorage { | |||
| this.jsapiTicketExpiresTime = jsapiTicketExpiresTime; | |||
| } | |||
| public void setCardApiTicket(String cardApiTicket) { | |||
| this.cardApiTicket = cardApiTicket; | |||
| } | |||
| public long getCardApiTicketExpiresTime() { | |||
| return this.cardApiTicketExpiresTime; | |||
| } | |||
| @@ -25,10 +25,10 @@ public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { | |||
| @Override | |||
| public boolean isAccessTokenExpired() { | |||
| return getAccessToken() == null ? true : false; | |||
| return getAccessToken() == null ? true : false; | |||
| } | |||
| @Override | |||
| @Override | |||
| public synchronized void updateAccessToken(String accessToken, int expiresInSeconds) { | |||
| jedis.set(ACCESS_TOKEN_KEY.concat(appId), accessToken); | |||
| jedis.expire(ACCESS_TOKEN_KEY.concat(appId), expiresInSeconds - 200); | |||
| @@ -87,4 +87,4 @@ public class WxMpInRedisConfigStorage extends WxMpInMemoryConfigStorage { | |||
| public void setJedis(Jedis jedis) { | |||
| this.jedis = jedis; | |||
| } | |||
| } | |||
| } | |||
| @@ -13,6 +13,7 @@ import java.util.Date; | |||
| * 客服接口 , | |||
| * 注意:命名采用kefu拼音的原因是:其英文CustomerService如果再加上Service后缀显得有点啰嗦,如果不加又显得表意不完整。 | |||
| * </pre> | |||
| * | |||
| * @author Binary Wang | |||
| */ | |||
| public interface WxMpKefuService { | |||
| @@ -2,9 +2,6 @@ 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.material.WxMpMaterial; | |||
| import me.chanjar.weixin.mp.bean.material.WxMpMaterialArticleUpdate; | |||
| import me.chanjar.weixin.mp.bean.material.WxMpMaterialNews; | |||
| import me.chanjar.weixin.mp.bean.material.*; | |||
| import java.io.File; | |||
| @@ -37,12 +34,13 @@ public interface WxMpMaterialService { | |||
| * 语音(voice):2M,播放长度不超过60s,支持AMR\MP3格式 | |||
| * 视频(video):10MB,支持MP4格式 | |||
| * 缩略图(thumb):64KB,支持JPG格式 | |||
| *媒体文件在后台保存时间为3天,即3天后media_id失效。 | |||
| * 媒体文件在后台保存时间为3天,即3天后media_id失效。 | |||
| * 详情请见: <a href="http://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1444738726&token=&lang=zh_CN">新增临时素材</a> | |||
| * 接口url格式:https://api.weixin.qq.com/cgi-bin/media/upload?access_token=ACCESS_TOKEN&type=TYPE | |||
| * </pre> | |||
| * | |||
| * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} | |||
| * @param file 文件对象 | |||
| * @param file 文件对象 | |||
| * @throws WxErrorException | |||
| * @see #mediaUpload(String, String, InputStream) | |||
| */ | |||
| @@ -106,12 +104,12 @@ public interface WxMpMaterialService { | |||
| * 接口url格式:https://api.weixin.qq.com/cgi-bin/material/add_material?access_token=ACCESS_TOKEN&type=TYPE | |||
| * | |||
| * 除了3天就会失效的临时素材外,开发者有时需要永久保存一些素材,届时就可以通过本接口新增永久素材。 | |||
| 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 | |||
| 请注意: | |||
| 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 | |||
| 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 | |||
| 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 | |||
| 4、调用该接口需https协议 | |||
| * 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 | |||
| * 请注意: | |||
| * 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 | |||
| * 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 | |||
| * 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 | |||
| * 4、调用该接口需https协议 | |||
| * </pre> | |||
| * | |||
| * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts} | |||
| @@ -127,12 +125,12 @@ public interface WxMpMaterialService { | |||
| * 接口url格式:https://api.weixin.qq.com/cgi-bin/material/add_news?access_token=ACCESS_TOKEN | |||
| * | |||
| * 除了3天就会失效的临时素材外,开发者有时需要永久保存一些素材,届时就可以通过本接口新增永久素材。 | |||
| 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 | |||
| 请注意: | |||
| 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 | |||
| 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 | |||
| 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 | |||
| 4、调用该接口需https协议 | |||
| * 永久图片素材新增后,将带有URL返回给开发者,开发者可以在腾讯系域名内使用(腾讯系域名外使用,图片将被屏蔽)。 | |||
| * 请注意: | |||
| * 1、新增的永久素材也可以在公众平台官网素材管理模块中看到 | |||
| * 2、永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000,其他类型为1000 | |||
| * 3、素材的格式大小等要求与公众平台官网一致。具体是,图片大小不超过2M,支持bmp/png/jpeg/jpg/gif格式,语音大小不超过5M,长度不超过60秒,支持mp3/wma/wav/amr格式 | |||
| * 4、调用该接口需https协议 | |||
| * </pre> | |||
| * | |||
| * @param news 上传的图文消息, 请看{@link WxMpMaterialNews} | |||