diff --git a/CHANGE.md b/CHANGE.md
index 8f5087d1..39236993 100644
--- a/CHANGE.md
+++ b/CHANGE.md
@@ -683,4 +683,8 @@
* 2016-05-07
- + version upgrade to 1.6.9
\ No newline at end of file
+ + version upgrade to 1.6.9
+
+* 2016-05-12
+
+ + 添加MemcacheTokenStorager支持
\ No newline at end of file
diff --git a/pom.xml b/pom.xml
index 3fed2489..bae4e08b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -229,10 +229,6 @@
org.apache.maven.plugins
maven-javadoc-plugin
-
- org.apache.maven.plugins
- maven-gpg-plugin
-
diff --git a/weixin4j-base/CHANGE.md b/weixin4j-base/CHANGE.md
index 688ce874..fc34c5f1 100644
--- a/weixin4j-base/CHANGE.md
+++ b/weixin4j-base/CHANGE.md
@@ -145,4 +145,8 @@
+ 新增海关接口
- + 添加日志支持
\ No newline at end of file
+ + 添加日志支持
+
+* 2016-05-12
+
+ + 添加MemcacheTokenStorager支持
\ No newline at end of file
diff --git a/weixin4j-base/pom.xml b/weixin4j-base/pom.xml
index f4342253..ce8cfc0c 100644
--- a/weixin4j-base/pom.xml
+++ b/weixin4j-base/pom.xml
@@ -45,6 +45,12 @@
2.6.0
true
+
+ com.meetup
+ memcached-client
+ 2.6.6
+ true
+
org.slf4j
slf4j-api
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java
index 203d3e89..015cad6b 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java
@@ -12,7 +12,7 @@ import com.foxinmy.weixin4j.util.FileUtil;
import com.foxinmy.weixin4j.xml.XmlStream;
/**
- * 用FILE保存TOKEN
+ * 用File形式保存Token信息
*
* @className FileTokenStorager
* @author jy
@@ -29,14 +29,17 @@ public class FileTokenStorager implements TokenStorager {
@Override
public Token lookup(String cacheKey) throws WeixinException {
- File token_file = new File(String.format("%s/%s.xml", cachePath, cacheKey));
+ File token_file = new File(String.format("%s/%s.xml", cachePath,
+ cacheKey));
try {
if (token_file.exists()) {
- Token token = XmlStream.fromXML(new FileInputStream(token_file), Token.class);
+ Token token = XmlStream.fromXML(
+ new FileInputStream(token_file), Token.class);
if (token.getCreateTime() < 0) {
return token;
}
- if ((token.getCreateTime() + (token.getExpiresIn() * 1000l) - CUTMS) > System.currentTimeMillis()) {
+ if ((token.getCreateTime() + (token.getExpiresIn() * 1000l) - CUTMS) > System
+ .currentTimeMillis()) {
return token;
}
}
@@ -49,7 +52,10 @@ public class FileTokenStorager implements TokenStorager {
@Override
public void caching(String cacheKey, Token token) throws WeixinException {
try {
- XmlStream.toXML(token, new FileOutputStream(new File(String.format("%s/%s.xml", cachePath, cacheKey))));
+ XmlStream.toXML(
+ token,
+ new FileOutputStream(new File(String.format("%s/%s.xml",
+ cachePath, cacheKey))));
} catch (IOException e) {
throw new WeixinException(e);
}
@@ -58,10 +64,12 @@ public class FileTokenStorager implements TokenStorager {
@Override
public Token evict(String cacheKey) throws WeixinException {
Token token = null;
- File token_file = new File(String.format("%s/%s.xml", cachePath, cacheKey));
+ File token_file = new File(String.format("%s/%s.xml", cachePath,
+ cacheKey));
try {
if (token_file.exists()) {
- token = XmlStream.fromXML(new FileInputStream(token_file), Token.class);
+ token = XmlStream.fromXML(new FileInputStream(token_file),
+ Token.class);
token_file.delete();
}
} catch (IOException e) {
@@ -75,8 +83,10 @@ public class FileTokenStorager implements TokenStorager {
File[] files = new File(cachePath).listFiles(new FileFilter() {
@Override
public boolean accept(File file) {
- return file.isFile() && file.getName().startsWith(PREFIX)
- && "xml".equals(FileUtil.getFileExtension(file.getName()));
+ return file.isFile()
+ && file.getName().startsWith(PREFIX)
+ && "xml".equals(FileUtil.getFileExtension(file
+ .getName()));
}
});
for (File token : files) {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/MemcacheTokenStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/MemcacheTokenStorager.java
new file mode 100644
index 00000000..93414a9a
--- /dev/null
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/MemcacheTokenStorager.java
@@ -0,0 +1,216 @@
+package com.foxinmy.weixin4j.token;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+import com.danga.MemCached.MemCachedClient;
+import com.danga.MemCached.SockIOPool;
+import com.foxinmy.weixin4j.exception.WeixinException;
+import com.foxinmy.weixin4j.model.Token;
+
+/**
+ * 用Memcache保存Token信息(推荐使用)
+ *
+ * @className MemcacheTokenStorager
+ * @author jy
+ * @date 2016年5月11日
+ * @since JDK 1.6
+ * @see
+ */
+public class MemcacheTokenStorager implements TokenStorager {
+
+ private final MemCachedClient mc;
+
+ public MemcacheTokenStorager(MemcachePoolConfig poolConfig) {
+ mc = new MemCachedClient();
+ poolConfig.initSocketIO();
+ }
+
+ @Override
+ public Token lookup(String cacheKey) throws WeixinException {
+ return (Token) mc.get(cacheKey);
+ }
+
+ @Override
+ public void caching(String cacheKey, Token token) throws WeixinException {
+ if (token.getExpiresIn() > 0) {
+ mc.set(cacheKey, token,
+ new Date(token.getCreateTime() + token.getExpiresIn()
+ * 1000 - CUTMS));
+ } else {
+ mc.set(cacheKey, token);
+ }
+ }
+
+ @Override
+ public Token evict(String cacheKey) throws WeixinException {
+ Token token = lookup(cacheKey);
+ mc.delete(cacheKey);
+ return token;
+ }
+
+ @Override
+ public void clear() throws WeixinException {
+ throw new UnsupportedOperationException();
+ }
+
+ public static class MemcachePoolConfig {
+ public final static String HOST = "localhost";
+ public final static int PORT = 11211;
+ public final static int WEIGHT = 1;
+
+ public static int minConn = 5;
+ public static int initConn = 5;
+ public static int maxConn = 100;
+ public static long maxIdle = 300000L;
+ public static long maxBusyTime = 30000L;
+ public static int socketTO = 3000;
+ public static int socketConnectTO = 3000;
+ public static boolean failover = true;
+ public static boolean failback = true;
+ public static boolean nagle = false;
+ public static boolean aliveCheck = false;
+ public static final int consistentHash = 3;
+ public static final int mainSleep = 30000;
+
+ private static SockIOPool pool;
+ static {
+ pool = SockIOPool.getInstance();
+ pool.setFailback(failback);
+ pool.setFailover(failover);
+ pool.setMaxBusyTime(maxBusyTime);
+ pool.setMaxConn(maxConn);
+ pool.setMaxIdle(maxIdle);
+ pool.setMinConn(minConn);
+ pool.setNagle(nagle);
+ pool.setSocketConnectTO(socketConnectTO);
+ pool.setSocketTO(socketTO);
+ pool.setAliveCheck(aliveCheck);
+ pool.setHashingAlg(consistentHash);
+ pool.setInitConn(initConn);
+ pool.setMaintSleep(maxBusyTime);
+ }
+
+ private List configs;
+ private String[] servers;
+ private Integer[] weights;
+
+ /**
+ * {localhost:11211,1}
+ */
+ public MemcachePoolConfig() {
+ this(HOST, PORT, WEIGHT);
+ }
+
+ /**
+ * {host:11211,1}
+ *
+ * @param host
+ * 主机
+ */
+ public MemcachePoolConfig(String host) {
+ this(host, PORT);
+ }
+
+ /**
+ * {host:port,1}
+ *
+ * @param host
+ * 主机
+ * @param port
+ * 端口
+ */
+ public MemcachePoolConfig(String host, int port) {
+ this(host, port, WEIGHT);
+ }
+
+ /**
+ * {host:port,weight}
+ *
+ * @param host
+ * 主机
+ * @param port
+ * 端口
+ * @param weight
+ * 权重
+ */
+ public MemcachePoolConfig(String host, int port, int weight) {
+ configs = new ArrayList();
+ configs.add(new MemcacheConfig(host, port, weight));
+ }
+
+ public MemcachePoolConfig addServer(String host) {
+ return addServer(host, PORT, WEIGHT);
+ }
+
+ public MemcachePoolConfig addServer(String host, int port) {
+ return addServer(host, port, WEIGHT);
+ }
+
+ public MemcachePoolConfig addServer(String host, int port, int weight) {
+ configs.add(new MemcacheConfig(host, port, weight));
+ return this;
+ }
+
+ private void initConfig() {
+ if (servers == null || weights == null) {
+ servers = new String[configs.size()];
+ weights = new Integer[configs.size()];
+ for (int i = 0; i < configs.size(); i++) {
+ servers[i] = configs.get(i).getServer();
+ weights[i] = configs.get(i).getWeight();
+ }
+ }
+ }
+
+ private void initSocketIO() {
+ pool.setServers(getServers());
+ pool.setWeights(getWeights());
+ if (pool.isInitialized()) {
+ pool.shutDown();
+ }
+ pool.initialize();
+ }
+
+ public String[] getServers() {
+ initConfig();
+ return servers;
+ }
+
+ public Integer[] getWeights() {
+ initConfig();
+ return weights;
+ }
+
+ @Override
+ public String toString() {
+ return "MemcachePoolConfig [" + configs + "]";
+ }
+
+ private static class MemcacheConfig {
+ private String host;
+ private int port;
+ private int weight;
+
+ public MemcacheConfig(String host, int port, int weight) {
+ this.host = host;
+ this.port = port;
+ this.weight = weight;
+ }
+
+ public String getServer() {
+ return String.format("%s:%d", host, port);
+ }
+
+ public int getWeight() {
+ return weight;
+ }
+
+ @Override
+ public String toString() {
+ return String.format("{%s:%d,%d}", host, port, weight);
+ }
+ }
+ }
+}
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/MemoryTokenStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/MemoryTokenStorager.java
index 3436bde3..a82a25a4 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/MemoryTokenStorager.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/MemoryTokenStorager.java
@@ -7,7 +7,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token;
/**
- * 用内存保存TOKEN(不推荐使用)
+ * 用内存保存Token信息(不推荐使用)
*
* @className MemoryTokenStorager
* @author jy
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/README.md b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/README.md
index 901dd211..6075d3d4 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/README.md
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/README.md
@@ -8,4 +8,6 @@
* FileTokenStorager 是系统默认的token存储策略实现
-* RedisTokenStorager 如果服务器支持redis,推荐使用(需要自己添加jedis包)
+* RedisTokenStorager 使用redis保存token(需要自行添加客户端包,[jedis](https://github.com/xetorthio/jedis))
+
+* MemcacheTokenStorager 使用memcache保存token(需要自行添加客户端包,[Memcached-Java-Client](https://github.com/gwhalin/Memcached-Java-Client))
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/RedisTokenStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/RedisTokenStorager.java
index 3cfd78b7..4bd4ec74 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/RedisTokenStorager.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/RedisTokenStorager.java
@@ -13,7 +13,7 @@ import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token;
/**
- * 用REDIS保存TOKEN(推荐使用)
+ * 用Redis保存Token信息(推荐使用)
*
* @className RedisTokenStorager
* @author jy
@@ -24,15 +24,16 @@ public class RedisTokenStorager implements TokenStorager {
private JedisPool jedisPool;
+ public final static String HOST = "localhost";
public final static int PORT = 6379;
public final static int MAX_TOTAL = 50;
public final static int MAX_IDLE = 5;
- public final static int MAX_WAIT_MILLIS = 2000;
+ public final static int MAX_WAIT_MILLIS = 3000;
public final static boolean TEST_ON_BORROW = false;
public final static boolean TEST_ON_RETURN = true;
public RedisTokenStorager() {
- this("localhost", PORT);
+ this(HOST, PORT);
}
public RedisTokenStorager(String host, int port) {
@@ -45,7 +46,8 @@ public class RedisTokenStorager implements TokenStorager {
this.jedisPool = new JedisPool(jedisPoolConfig, host, port);
}
- public RedisTokenStorager(String host, int port, JedisPoolConfig jedisPoolConfig) {
+ public RedisTokenStorager(String host, int port,
+ JedisPoolConfig jedisPoolConfig) {
this(new JedisPool(jedisPoolConfig, host, port));
}
@@ -77,7 +79,8 @@ public class RedisTokenStorager implements TokenStorager {
jedis = jedisPool.getResource();
jedis.hmset(cacheKey, token2map(token));
if (token.getExpiresIn() > 0) {
- jedis.expire(cacheKey, token.getExpiresIn() - (int) (CUTMS / 1000l));
+ jedis.expire(cacheKey, token.getExpiresIn()
+ - (int) (CUTMS / 1000l));
}
} finally {
if (jedis != null) {
diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenStorager.java
index 61de6eac..089567a2 100644
--- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenStorager.java
+++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/TokenStorager.java
@@ -13,6 +13,7 @@ import com.foxinmy.weixin4j.model.Token;
* @see MemoryTokenStorager
* @see FileTokenStorager
* @see RedisTokenStorager
+ * @see MemcacheTokenStorager
*/
public interface TokenStorager extends CacheStorager {
/**
diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/CardColor.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/CardColor.java
new file mode 100644
index 00000000..cf7e5aec
--- /dev/null
+++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/CardColor.java
@@ -0,0 +1,48 @@
+package com.foxinmy.weixin4j.mp.type;
+
+/**
+ * 卡券颜色
+ *
+ * @className CardColor
+ * @author jy
+ * @date 2016年4月4日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CardColor {
+ COLOR010(99, 179, 89, "#63b359"), COLOR020(44, 159, 103, "#2c9f67"), COLOR030(
+ 80, 159, 201, "#509fc9"), COLOR040(88, 133, 207, "#5885cf"), COLOR050(
+ 144, 98, 192, "#9062c0"), COLOR060(208, 154, 69, "#d09a45"), COLOR070(
+ 228, 117, 56, "#e4b138"), COLOR080(238, 144, 60, "#ee903c"), COLOR081(
+ 240, 133, 0, "#f08500"), COLOR082(169, 217, 45, "#a9d92d"), COLOR090(
+ 221, 101, 73, "#dd6549"), COLOR0100(204, 70, 61, "#cc463d"), COLOR0101(
+ 207, 62, 54, "#cf3e36"), COLOR0102(94, 102, 113, "#5E6671");
+ private int r;
+ private int g;
+ private int b;
+ private String hex;
+
+ CardColor(int r, int g, int b, String hex) {
+ this.r = r;
+ this.g = g;
+ this.b = b;
+ this.hex = hex;
+ ;
+ }
+
+ public int getR() {
+ return r;
+ }
+
+ public int getG() {
+ return g;
+ }
+
+ public int getB() {
+ return b;
+ }
+
+ public String getHex() {
+ return hex;
+ }
+}
diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/CardType.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/CardType.java
new file mode 100644
index 00000000..7440a6d1
--- /dev/null
+++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/CardType.java
@@ -0,0 +1,33 @@
+package com.foxinmy.weixin4j.mp.type;
+
+/**
+ * 卡券类型
+ *
+ * @className CardType
+ * @author jy
+ * @date 2016年4月4日
+ * @since JDK 1.6
+ * @see
+ */
+public enum CardType {
+ /**
+ * 团购券
+ */
+ GROUPON,
+ /**
+ * 代金券
+ */
+ CASH,
+ /**
+ * 折扣券
+ */
+ DISCOUNT,
+ /**
+ * 兑换券
+ */
+ GIFT,
+ /**
+ * 优惠券
+ */
+ GENERAL_COUPON;
+}
diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTokenCreator.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTokenCreator.java
index 3eaa35b0..9a4ae6f8 100644
--- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTokenCreator.java
+++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/token/WeixinTokenCreator.java
@@ -46,7 +46,8 @@ public class WeixinTokenCreator extends AbstractTokenCreator {
@Override
public Token createToken() throws WeixinException {
- String tokenUrl = String.format(URLConsts.ASSESS_TOKEN_URL, corpid, corpsecret);
+ String tokenUrl = String.format(URLConsts.ASSESS_TOKEN_URL, corpid,
+ corpsecret);
WeixinResponse response = weixinExecutor.get(tokenUrl);
Token token = response.getAsObject(new TypeReference() {
});