@@ -0,0 +1,26 @@ | |||
package chanjarster.weixin.api; | |||
import chanjarster.weixin.bean.WxAccessToken; | |||
/** | |||
* 微信配置的工具类 | |||
* @author chanjarster | |||
* | |||
*/ | |||
public interface WxConfigProvider { | |||
public void updateAccessToken(WxAccessToken accessToken); | |||
public void updateAccessToken(String accessToken, int expiresIn); | |||
public String getAccessToken(); | |||
public String getAppId(); | |||
public String getSecret(); | |||
public String getToken(); | |||
public int getExpiresIn(); | |||
} |
@@ -1,6 +1,6 @@ | |||
package chanjarster.weixin.service; | |||
package chanjarster.weixin.api; | |||
public class WxMsgType { | |||
public class WxConsts { | |||
public static final String TEXT = "text"; | |||
public static final String IMAGE = "image"; |
@@ -0,0 +1,47 @@ | |||
package chanjarster.weixin.api; | |||
import chanjarster.weixin.bean.WxAccessToken; | |||
/** | |||
* 基于内存的微信配置provider | |||
* @author chanjarster | |||
* | |||
*/ | |||
public class WxMemoryConfigProvider implements WxConfigProvider { | |||
protected String appId; | |||
protected String secret; | |||
protected String token; | |||
protected String accessToken; | |||
protected int expiresIn; | |||
public void updateAccessToken(WxAccessToken accessToken) { | |||
updateAccessToken(accessToken.getAccess_token(), accessToken.getExpires_in()); | |||
} | |||
public void updateAccessToken(String accessToken, int expiresIn) { | |||
this.accessToken = accessToken; | |||
this.expiresIn = expiresIn; | |||
} | |||
public String getAccessToken() { | |||
return this.accessToken; | |||
} | |||
public String getAppId() { | |||
return this.appId; | |||
} | |||
public String getSecret() { | |||
return this.secret; | |||
} | |||
public String getToken() { | |||
return this.token; | |||
} | |||
public int getExpiresIn() { | |||
return this.expiresIn; | |||
} | |||
} |
@@ -0,0 +1,16 @@ | |||
package chanjarster.weixin.api; | |||
import java.util.Map; | |||
import chanjarster.weixin.bean.WxXmlMessage; | |||
/** | |||
* 处理微信推送消息的处理器 | |||
* @author chanjarster | |||
* | |||
*/ | |||
public interface WxMessageHandler { | |||
public void handle(WxXmlMessage wxMessage, Map<String, Object> context); | |||
} |
@@ -1,8 +1,8 @@ | |||
package chanjarster.weixin.service; | |||
package chanjarster.weixin.api; | |||
import java.util.Map; | |||
import chanjarster.weixin.out.WxUserMessage; | |||
import chanjarster.weixin.bean.WxXmlMessage; | |||
/** | |||
@@ -17,6 +17,6 @@ public interface WxMessageInterceptor { | |||
* @param wxMessage | |||
* @return true代表OK,false代表不OK | |||
*/ | |||
public boolean intercept(WxUserMessage wxMessage, Map<String, Object> context); | |||
public boolean intercept(WxXmlMessage wxMessage, Map<String, Object> context); | |||
} |
@@ -1,11 +1,11 @@ | |||
package chanjarster.weixin.service; | |||
package chanjarster.weixin.api; | |||
import java.util.ArrayList; | |||
import java.util.HashMap; | |||
import java.util.List; | |||
import java.util.Map; | |||
import chanjarster.weixin.out.WxUserMessage; | |||
import chanjarster.weixin.bean.WxXmlMessage; | |||
/** | |||
* 微信消息路由器,通过代码化的配置,把来自微信的消息交给某个的handler处理 | |||
@@ -28,7 +28,7 @@ public class WxMessageRouter { | |||
* 处理微信消息 | |||
* @param wxMessage | |||
*/ | |||
public void route(WxUserMessage wxMessage) { | |||
public void route(WxXmlMessage wxMessage) { | |||
for (Rule rule : rules) { | |||
boolean doNext = rule.service(wxMessage); | |||
if (!doNext) { | |||
@@ -148,7 +148,7 @@ public class WxMessageRouter { | |||
return this.routerBuilder; | |||
} | |||
protected boolean test(WxUserMessage wxMessage) { | |||
protected boolean test(WxXmlMessage wxMessage) { | |||
return | |||
(this.msgType == null || this.msgType.equals(wxMessage.getMsgType())) | |||
&& | |||
@@ -165,7 +165,7 @@ public class WxMessageRouter { | |||
* @param wxMessage | |||
* @return true 代表继续执行别的router,false 代表停止执行别的router | |||
*/ | |||
protected boolean service(WxUserMessage wxMessage) { | |||
protected boolean service(WxXmlMessage wxMessage) { | |||
// 如果不匹配本规则,那么接着执行后面的Rule | |||
if (!test(wxMessage)) { | |||
return true; |
@@ -0,0 +1,54 @@ | |||
package chanjarster.weixin.api; | |||
import chanjarster.weixin.bean.WxCustomMessage; | |||
import chanjarster.weixin.bean.WxMenu; | |||
import chanjarster.weixin.exception.WxErrorException; | |||
/** | |||
* 微信API的Service | |||
*/ | |||
public interface WxService { | |||
/** | |||
* 刷新access_token,这个方法是线程安全的 | |||
* 且在高并发情况下只会刷新一次,而不是刷新多次 | |||
* 在非必要情况下不要主动调用此方法 | |||
* 本service的所有方法都会在access_token过期的情况下调用此方法 | |||
* | |||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token | |||
* @throws WxErrorException | |||
*/ | |||
public void refreshAccessToken() throws WxErrorException; | |||
/** | |||
* 发送客服消息 | |||
* @param message | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
public String sendCustomMessage(WxCustomMessage message) throws WxErrorException; | |||
/** | |||
* 创建菜单 | |||
* @param menu | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
public String createMenu(WxMenu menu) throws WxErrorException; | |||
/** | |||
* 删除菜单 | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
public String deleteMenu() throws WxErrorException; | |||
/** | |||
* 获得菜单 | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
public WxMenu getMenu() throws WxErrorException; | |||
public void setWxConfigProvider(WxConfigProvider wxConfigProvider); | |||
} |
@@ -1,4 +1,4 @@ | |||
package chanjarster.weixin.service; | |||
package chanjarster.weixin.api; | |||
import java.io.IOException; | |||
import java.nio.charset.Charset; | |||
@@ -14,11 +14,11 @@ import org.apache.http.impl.client.BasicResponseHandler; | |||
import org.apache.http.impl.client.CloseableHttpClient; | |||
import org.apache.http.impl.client.HttpClients; | |||
import chanjarster.weixin.bean.WxAccessToken; | |||
import chanjarster.weixin.bean.WxCustomMessage; | |||
import chanjarster.weixin.bean.WxError; | |||
import chanjarster.weixin.bean.WxMenu; | |||
import chanjarster.weixin.exception.WxErrorException; | |||
import chanjarster.weixin.in.WxAccessToken; | |||
import chanjarster.weixin.in.WxError; | |||
import chanjarster.weixin.out.WxCustomMessage; | |||
import chanjarster.weixin.out.WxMenu; | |||
public class WxServiceImpl implements WxService { | |||
@@ -35,12 +35,6 @@ public class WxServiceImpl implements WxService { | |||
protected WxConfigProvider wxConfigProvider; | |||
/** | |||
* 获得access_token | |||
* 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=获取access_token | |||
* @return | |||
* @throws WxErrorException | |||
*/ | |||
public void refreshAccessToken() throws WxErrorException { | |||
if (!GLOBAL_ACCESS_TOKEN_REFRESH_FLAG.getAndSet(true)) { | |||
try { |
@@ -1,4 +1,4 @@ | |||
package chanjarster.weixin.in; | |||
package chanjarster.weixin.bean; | |||
import chanjarster.weixin.util.WxGsonBuilder; | |||
@@ -1,4 +1,4 @@ | |||
package chanjarster.weixin.out; | |||
package chanjarster.weixin.bean; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
@@ -6,7 +6,7 @@ import java.util.List; | |||
import chanjarster.weixin.util.WxGsonBuilder; | |||
/** | |||
* 回复给用户的客服消息 | |||
* 客服消息 | |||
* @author chanjarster | |||
* | |||
*/ |
@@ -1,4 +1,4 @@ | |||
package chanjarster.weixin.in; | |||
package chanjarster.weixin.bean; | |||
import chanjarster.weixin.util.WxGsonBuilder; | |||
@@ -1,8 +1,12 @@ | |||
package chanjarster.weixin.out; | |||
package chanjarster.weixin.bean; | |||
import java.io.InputStream; | |||
import java.io.InputStreamReader; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
import chanjarster.weixin.util.WxGsonBuilder; | |||
/** | |||
* 公众号菜单 | |||
* @author chanjarster | |||
@@ -20,6 +24,18 @@ public class WxMenu { | |||
this.button = button; | |||
} | |||
public String toJson() { | |||
return WxGsonBuilder.create().toJson(this); | |||
} | |||
public static WxMenu fromJson(String json) { | |||
return WxGsonBuilder.create().fromJson(json, WxMenu.class); | |||
} | |||
public static WxMenu fromJson(InputStream is) { | |||
return WxGsonBuilder.create().fromJson(new InputStreamReader(is), WxMenu.class); | |||
} | |||
public static class WxMenuButton { | |||
protected String type; |
@@ -1,10 +1,11 @@ | |||
package chanjarster.weixin.out; | |||
package chanjarster.weixin.bean; | |||
import java.io.InputStream; | |||
import javax.xml.bind.JAXBException; | |||
import javax.xml.bind.annotation.XmlAccessType; | |||
import javax.xml.bind.annotation.XmlAccessorType; | |||
import javax.xml.bind.annotation.XmlElement; | |||
import javax.xml.bind.annotation.XmlRegistry; | |||
import javax.xml.bind.annotation.XmlRootElement; | |||
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter; | |||
@@ -13,7 +14,7 @@ import chanjarster.weixin.util.XmlTransformer; | |||
/** | |||
* <pre> | |||
* 微信推送过来的消息,同时也是同步回复给用户的消息 | |||
* 微信推送过来的消息,也是同步回复给用户的消息,xml格式 | |||
* 相关字段的解释看微信开发者文档: | |||
* http://mp.weixin.qq.com/wiki/index.php?title=接收普通消息 | |||
* http://mp.weixin.qq.com/wiki/index.php?title=接收事件推送 | |||
@@ -24,7 +25,7 @@ import chanjarster.weixin.util.XmlTransformer; | |||
*/ | |||
@XmlRootElement(name = "xml") | |||
@XmlAccessorType(XmlAccessType.FIELD) | |||
public class WxUserMessage { | |||
public class WxXmlMessage { | |||
/////////////////////// | |||
// 以下都是微信推送过来的消息的xml的element所对应的属性 | |||
@@ -288,21 +289,31 @@ public class WxUserMessage { | |||
public String toXml() { | |||
try { | |||
return XmlTransformer.toXml(WxUserMessage.class, this); | |||
return XmlTransformer.toXml(WxXmlMessage.class, this); | |||
} catch (JAXBException e) { | |||
e.printStackTrace(); | |||
} | |||
return ""; | |||
} | |||
public static WxUserMessage fromXml(String xml) { | |||
public static WxXmlMessage fromXml(String xml) { | |||
try { | |||
return XmlTransformer.fromXml(WxUserMessage.class, xml); | |||
return XmlTransformer.fromXml(WxXmlMessage.class, xml); | |||
} catch (JAXBException e) { | |||
e.printStackTrace(); | |||
} | |||
return null; | |||
} | |||
public static WxXmlMessage fromXml(InputStream is) { | |||
try { | |||
return XmlTransformer.fromXml(WxXmlMessage.class, is); | |||
} catch (JAXBException e) { | |||
e.printStackTrace(); | |||
} | |||
return null; | |||
} | |||
@Override | |||
public int hashCode() { | |||
final int prime = 31; | |||
@@ -338,7 +349,7 @@ public class WxUserMessage { | |||
if (this == obj) return true; | |||
if (obj == null) return false; | |||
if (getClass() != obj.getClass()) return false; | |||
WxUserMessage other = (WxUserMessage) obj; | |||
WxXmlMessage other = (WxXmlMessage) obj; | |||
if (Content == null) { | |||
if (other.Content != null) return false; | |||
} else if (!Content.equals(other.Content)) return false; |
@@ -1,6 +1,6 @@ | |||
package chanjarster.weixin.exception; | |||
import chanjarster.weixin.in.WxError; | |||
import chanjarster.weixin.bean.WxError; | |||
public class WxErrorException extends Exception { | |||
@@ -1,15 +0,0 @@ | |||
package chanjarster.weixin.service; | |||
public interface WxConfigProvider { | |||
public void updateAccessToken(String accessToken, Integer expiresIn); | |||
public String getAccessToken(); | |||
public String getAppId(); | |||
public String getSecret(); | |||
public String getToken(); | |||
} |
@@ -1,16 +0,0 @@ | |||
package chanjarster.weixin.service; | |||
import java.util.Map; | |||
import chanjarster.weixin.out.WxUserMessage; | |||
/** | |||
* 处理微信推送消息的处理器 | |||
* @author chanjarster | |||
* | |||
*/ | |||
public interface WxMessageHandler { | |||
public void handle(WxUserMessage wxMessage, Map<String, Object> context); | |||
} |
@@ -1,23 +0,0 @@ | |||
package chanjarster.weixin.service; | |||
import chanjarster.weixin.exception.WxErrorException; | |||
import chanjarster.weixin.out.WxCustomMessage; | |||
import chanjarster.weixin.out.WxMenu; | |||
/** | |||
* 微信相关的常量 | |||
*/ | |||
public interface WxService { | |||
public void refreshAccessToken() throws WxErrorException; | |||
public String sendCustomMessage(WxCustomMessage message) throws WxErrorException; | |||
public String createMenu(WxMenu menu) throws WxErrorException; | |||
public String deleteMenu() throws WxErrorException; | |||
public WxMenu getMenu() throws WxErrorException; | |||
public void setWxConfigProvider(WxConfigProvider wxConfigProvider); | |||
} |
@@ -0,0 +1,115 @@ | |||
/* | |||
* KINGSTAR MEDIA SOLUTIONS Co.,LTD. Copyright c 2005-2013. All rights reserved. | |||
* | |||
* This source code is the property of KINGSTAR MEDIA SOLUTIONS LTD. It is intended | |||
* only for the use of KINGSTAR MEDIA application development. Reengineering, reproduction | |||
* arose from modification of the original source, or other redistribution of this source | |||
* is not permitted without written permission of the KINGSTAR MEDIA SOLUTIONS LTD. | |||
*/ | |||
package chanjarster.weixin.util; | |||
import com.google.gson.JsonElement; | |||
import com.google.gson.JsonObject; | |||
public class GsonHelper { | |||
public static boolean isNull(JsonElement element) { | |||
return element == null || element.isJsonNull(); | |||
} | |||
public static boolean isNotNull(JsonElement element) { | |||
return !isNull(element); | |||
} | |||
public static Long getLong(JsonObject json, String property) { | |||
return getAsLong(json.get(property)); | |||
} | |||
public static long getPrimitiveLong(JsonObject json, String property) { | |||
return getAsPrimitiveLong(json.get(property)); | |||
} | |||
public static Integer getInteger(JsonObject json, String property) { | |||
return getAsInteger(json.get(property)); | |||
} | |||
public static int getPrimitiveInteger(JsonObject json, String property) { | |||
return getAsPrimitiveInt(json.get(property)); | |||
} | |||
public static Double getDouble(JsonObject json, String property) { | |||
return getAsDouble(json.get(property)); | |||
} | |||
public static double getPrimitiveDouble(JsonObject json, String property) { | |||
return getAsPrimitiveDouble(json.get(property)); | |||
} | |||
public static Float getFloat(JsonObject json, String property) { | |||
return getAsFloat(json.get(property)); | |||
} | |||
public static float getPrimitiveFloat(JsonObject json, String property) { | |||
return getAsPrimitiveFloat(json.get(property)); | |||
} | |||
public static Boolean getBoolean(JsonObject json, String property) { | |||
return getAsBoolean(json.get(property)); | |||
} | |||
public static String getString(JsonObject json, String property) { | |||
return getAsString(json.get(property)); | |||
} | |||
public static String getAsString(JsonElement element) { | |||
return isNull(element) ? null : element.getAsString(); | |||
} | |||
public static Long getAsLong(JsonElement element) { | |||
return isNull(element) ? null : element.getAsLong(); | |||
} | |||
public static long getAsPrimitiveLong(JsonElement element) { | |||
Long r = getAsLong(element); | |||
return r == null ? 0l : r; | |||
} | |||
public static Integer getAsInteger(JsonElement element) { | |||
return isNull(element) ? null : element.getAsInt(); | |||
} | |||
public static int getAsPrimitiveInt(JsonElement element) { | |||
Integer r = getAsInteger(element); | |||
return r == null ? 0 : r; | |||
} | |||
public static Boolean getAsBoolean(JsonElement element) { | |||
return isNull(element) ? null : element.getAsBoolean(); | |||
} | |||
public static boolean getAsPrimitiveBool(JsonElement element) { | |||
Boolean r = getAsBoolean(element); | |||
return r == null ? false : r.booleanValue(); | |||
} | |||
public static Double getAsDouble(JsonElement element) { | |||
return isNull(element) ? null : element.getAsDouble(); | |||
} | |||
public static double getAsPrimitiveDouble(JsonElement element) { | |||
Double r = getAsDouble(element); | |||
return r == null ? 0d : r; | |||
} | |||
public static Float getAsFloat(JsonElement element) { | |||
return isNull(element) ? null : element.getAsFloat(); | |||
} | |||
public static float getAsPrimitiveFloat(JsonElement element) { | |||
Float r = getAsFloat(element); | |||
return r == null ? 0f : r; | |||
} | |||
} |
@@ -10,9 +10,9 @@ package chanjarster.weixin.util; | |||
import java.lang.reflect.Type; | |||
import chanjarster.weixin.out.WxCustomMessage; | |||
import chanjarster.weixin.out.WxCustomMessage.WxArticle; | |||
import chanjarster.weixin.service.WxMsgType; | |||
import chanjarster.weixin.api.WxConsts; | |||
import chanjarster.weixin.bean.WxCustomMessage; | |||
import chanjarster.weixin.bean.WxCustomMessage.WxArticle; | |||
import com.google.gson.JsonArray; | |||
import com.google.gson.JsonElement; | |||
@@ -32,25 +32,25 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag | |||
messageJson.addProperty("touser", message.getTouser()); | |||
messageJson.addProperty("msgtype", message.getMsgtype()); | |||
if (WxMsgType.TEXT.equals(message.getMsgtype())) { | |||
if (WxConsts.TEXT.equals(message.getMsgtype())) { | |||
JsonObject text = new JsonObject(); | |||
text.addProperty("content", message.getContent()); | |||
messageJson.add("text", text); | |||
} | |||
if (WxMsgType.IMAGE.equals(message.getMsgtype())) { | |||
if (WxConsts.IMAGE.equals(message.getMsgtype())) { | |||
JsonObject image = new JsonObject(); | |||
image.addProperty("media_id", message.getMedia_id()); | |||
messageJson.add("image", image); | |||
} | |||
if (WxMsgType.VOICE.equals(message.getMsgtype())) { | |||
if (WxConsts.VOICE.equals(message.getMsgtype())) { | |||
JsonObject voice = new JsonObject(); | |||
voice.addProperty("media_id", message.getMedia_id()); | |||
messageJson.add("voice", voice); | |||
} | |||
if (WxMsgType.VIDEO.equals(message.getMsgtype())) { | |||
if (WxConsts.VIDEO.equals(message.getMsgtype())) { | |||
JsonObject video = new JsonObject(); | |||
video.addProperty("media_id", message.getMedia_id()); | |||
video.addProperty("thumb_media_id", message.getThumb_media_id()); | |||
@@ -59,7 +59,7 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag | |||
messageJson.add("video", video); | |||
} | |||
if (WxMsgType.MUSIC.equals(message.getMsgtype())) { | |||
if (WxConsts.MUSIC.equals(message.getMsgtype())) { | |||
JsonObject music = new JsonObject(); | |||
music.addProperty("title", message.getTitle()); | |||
music.addProperty("description", message.getDescription()); | |||
@@ -69,7 +69,7 @@ public class WxCustomMessageGsonAdapter implements JsonSerializer<WxCustomMessag | |||
messageJson.add("music", music); | |||
} | |||
if (WxMsgType.NEWS.equals(message.getMsgtype())) { | |||
if (WxConsts.NEWS.equals(message.getMsgtype())) { | |||
JsonArray articleJsonArray = new JsonArray(); | |||
for (WxArticle article : message.getArticles()) { | |||
JsonObject articleJson = new JsonObject(); | |||
@@ -1,6 +1,7 @@ | |||
package chanjarster.weixin.util; | |||
import chanjarster.weixin.out.WxCustomMessage; | |||
import chanjarster.weixin.bean.WxCustomMessage; | |||
import chanjarster.weixin.bean.WxMenu; | |||
import com.google.gson.Gson; | |||
import com.google.gson.GsonBuilder; | |||
@@ -12,6 +13,7 @@ public class WxGsonBuilder { | |||
static { | |||
INSTANCE.disableHtmlEscaping(); | |||
INSTANCE.registerTypeAdapter(WxCustomMessage.class, new WxCustomMessageGsonAdapter()); | |||
INSTANCE.registerTypeAdapter(WxMenu.class, new WxMenuGsonAdapter()); | |||
} | |||
public static Gson create() { | |||
@@ -10,12 +10,15 @@ package chanjarster.weixin.util; | |||
import java.lang.reflect.Type; | |||
import chanjarster.weixin.out.WxMenu; | |||
import chanjarster.weixin.out.WxMenu.WxMenuButton; | |||
import chanjarster.weixin.bean.WxMenu; | |||
import chanjarster.weixin.bean.WxMenu.WxMenuButton; | |||
import com.google.gson.JsonArray; | |||
import com.google.gson.JsonDeserializationContext; | |||
import com.google.gson.JsonDeserializer; | |||
import com.google.gson.JsonElement; | |||
import com.google.gson.JsonObject; | |||
import com.google.gson.JsonParseException; | |||
import com.google.gson.JsonSerializationContext; | |||
import com.google.gson.JsonSerializer; | |||
@@ -24,14 +27,14 @@ import com.google.gson.JsonSerializer; | |||
* @author qianjia | |||
* | |||
*/ | |||
public class WxMenuGsonAdapter implements JsonSerializer<WxMenu> { | |||
public class WxMenuGsonAdapter implements JsonSerializer<WxMenu>, JsonDeserializer<WxMenu> { | |||
public JsonElement serialize(WxMenu menu, Type typeOfSrc, JsonSerializationContext context) { | |||
JsonObject json = new JsonObject(); | |||
JsonArray buttonArray = new JsonArray(); | |||
for (WxMenuButton button : menu.getButton()) { | |||
JsonObject buttonJson = serialize(button); | |||
JsonObject buttonJson = convertToJson(button); | |||
buttonArray.add(buttonJson); | |||
} | |||
json.add("button", buttonArray); | |||
@@ -39,17 +42,48 @@ public class WxMenuGsonAdapter implements JsonSerializer<WxMenu> { | |||
return json; | |||
} | |||
protected JsonObject serialize(WxMenuButton button) { | |||
protected JsonObject convertToJson(WxMenuButton button) { | |||
JsonObject buttonJson = new JsonObject(); | |||
buttonJson.addProperty("type", button.getType()); | |||
buttonJson.addProperty("name", button.getName()); | |||
// TODO 其他字段 | |||
if (button.getSub_button() == null || button.getSub_button().size() == 0) { | |||
buttonJson.addProperty("key", button.getKey()); | |||
buttonJson.addProperty("url", button.getUrl()); | |||
if (button.getSub_button() != null && button.getSub_button().size() > 0) { | |||
JsonArray buttonArray = new JsonArray(); | |||
for (WxMenuButton sub_button : button.getSub_button()) { | |||
buttonArray.add(serialize(sub_button)); | |||
buttonArray.add(convertToJson(sub_button)); | |||
} | |||
buttonJson.add("sub_button", buttonArray); | |||
} | |||
return buttonJson; | |||
} | |||
} | |||
public WxMenu deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { | |||
WxMenu menu = new WxMenu(); | |||
JsonArray buttonsJson = json.getAsJsonObject().get("button").getAsJsonArray(); | |||
for (int i = 0; i < buttonsJson.size(); i++) { | |||
JsonObject buttonJson = buttonsJson.get(i).getAsJsonObject(); | |||
WxMenuButton button = convertFromJson(buttonJson); | |||
menu.getButton().add(button); | |||
if (buttonJson.get("sub_button") == null || buttonJson.get("sub_button").isJsonNull()) { | |||
continue; | |||
} | |||
JsonArray sub_buttonsJson = buttonJson.get("sub_button").getAsJsonArray(); | |||
for (int j = 0; j < sub_buttonsJson.size(); j++) { | |||
JsonObject sub_buttonJson = sub_buttonsJson.get(j).getAsJsonObject(); | |||
button.getSub_button().add(convertFromJson(sub_buttonJson)); | |||
} | |||
} | |||
return menu; | |||
} | |||
protected WxMenuButton convertFromJson(JsonObject json) { | |||
WxMenuButton button = new WxMenuButton(); | |||
button.setName(GsonHelper.getString(json, "name")); | |||
button.setKey(GsonHelper.getString(json, "key")); | |||
button.setUrl(GsonHelper.getString(json, "url")); | |||
button.setType(GsonHelper.getString(json, "type")); | |||
return button; | |||
} | |||
} |
@@ -1,4 +1,4 @@ | |||
package chanjarster.weixin.service; | |||
package chanjarster.weixin.api; | |||
// TODO | |||
public class WxMessageRouterTest { |
@@ -1,4 +1,4 @@ | |||
package chanjarster.weixin.service; | |||
package chanjarster.weixin.api; | |||
import java.io.InputStream; | |||
@@ -12,14 +12,18 @@ import org.testng.Assert; | |||
import org.testng.annotations.DataProvider; | |||
import org.testng.annotations.Test; | |||
import chanjarster.weixin.api.WxConsts; | |||
import chanjarster.weixin.api.WxMemoryConfigProvider; | |||
import chanjarster.weixin.api.WxService; | |||
import chanjarster.weixin.api.WxServiceImpl; | |||
import chanjarster.weixin.bean.WxCustomMessage; | |||
import chanjarster.weixin.exception.WxErrorException; | |||
import chanjarster.weixin.out.WxCustomMessage; | |||
import chanjarster.weixin.util.XmlTransformer; | |||
public class WxServiceTest { | |||
@Test(dataProvider = "configs") | |||
public void testRefreshAccessToken(WxConfigProvider config) throws WxErrorException { | |||
public void testRefreshAccessToken(WxTestConfigProvider config) throws WxErrorException { | |||
String before = config.getAccessToken(); | |||
WxService wxService = new WxServiceImpl(); | |||
@@ -33,12 +37,12 @@ public class WxServiceTest { | |||
} | |||
@Test(dataProvider = "configs") | |||
public void sendCustomMessage(SimpleWxConfigProvider config) throws WxErrorException { | |||
public void sendCustomMessage(WxTestConfigProvider config) throws WxErrorException { | |||
WxService wxService = new WxServiceImpl(); | |||
wxService.setWxConfigProvider(config); | |||
WxCustomMessage message = new WxCustomMessage(); | |||
message.setMsgtype(WxMsgType.TEXT); | |||
message.setMsgtype(WxConsts.TEXT); | |||
message.setTouser(config.getOpenId()); | |||
message.setContent("欢迎使用教务系统微信公众号\n下面\n<a href=\"http://192.168.1.249:9180/eams-rc/login.action\">Hello World</a>"); | |||
@@ -56,7 +60,7 @@ public class WxServiceTest { | |||
*/ | |||
// 没有access_token | |||
InputStream is1 = ClassLoader.getSystemResourceAsStream("test-config.xml"); | |||
SimpleWxConfigProvider config1 = XmlTransformer.fromXml(SimpleWxConfigProvider.class, is1); | |||
WxTestConfigProvider config1 = XmlTransformer.fromXml(WxTestConfigProvider.class, is1); | |||
return new Object[][] { | |||
new Object[] { | |||
config1 | |||
@@ -66,47 +70,10 @@ public class WxServiceTest { | |||
@XmlRootElement(name = "xml") | |||
@XmlAccessorType(XmlAccessType.FIELD) | |||
public static class SimpleWxConfigProvider implements WxConfigProvider { | |||
private String appId; | |||
private String secret; | |||
private String accessToken = ""; | |||
private Integer expiresIn; | |||
private String token; | |||
private String openId; | |||
public void updateAccessToken(String accessToken, Integer expiresIn) { | |||
this.accessToken = accessToken; | |||
this.expiresIn = expiresIn; | |||
} | |||
public String getAccessToken() { | |||
return accessToken; | |||
} | |||
public String getAppId() { | |||
return appId; | |||
} | |||
public String getSecret() { | |||
return secret; | |||
} | |||
public String getToken() { | |||
return token; | |||
} | |||
public void setAppId(String appId) { | |||
this.appId = appId; | |||
} | |||
public void setSecret(String secret) { | |||
this.secret = secret; | |||
} | |||
public void setToken(String token) { | |||
this.token = token; | |||
} | |||
public Integer getExpiresIn() { | |||
return expiresIn; | |||
} | |||
public void setExpiresIn(Integer expiresIn) { | |||
this.expiresIn = expiresIn; | |||
} | |||
public void setAccessToken(String accessToken) { | |||
this.accessToken = accessToken; | |||
} | |||
public static class WxTestConfigProvider extends WxMemoryConfigProvider { | |||
protected String openId; | |||
public String getOpenId() { | |||
return openId; | |||
} |
@@ -0,0 +1,18 @@ | |||
package chanjarster.weixin.bean; | |||
import org.testng.Assert; | |||
import org.testng.annotations.Test; | |||
@Test | |||
public class WxAccessTokenTest { | |||
public void testFromJson() { | |||
String json = "{\"access_token\":\"ACCESS_TOKEN\",\"expires_in\":7200}"; | |||
WxAccessToken wxError = WxAccessToken.fromJson(json); | |||
Assert.assertEquals(wxError.getAccess_token(), "ACCESS_TOKEN"); | |||
Assert.assertTrue(wxError.getExpires_in() == 7200); | |||
} | |||
} |
@@ -1,18 +1,19 @@ | |||
package chanjarster.weixin.out; | |||
package chanjarster.weixin.bean; | |||
import org.testng.Assert; | |||
import org.testng.annotations.Test; | |||
import chanjarster.weixin.out.WxCustomMessage; | |||
import chanjarster.weixin.out.WxCustomMessage.WxArticle; | |||
import chanjarster.weixin.service.WxMsgType; | |||
import chanjarster.weixin.api.WxConsts; | |||
import chanjarster.weixin.bean.WxCustomMessage; | |||
import chanjarster.weixin.bean.WxCustomMessage.WxArticle; | |||
@Test | |||
public class WxCustomMessageTest { | |||
public void testTextReply() { | |||
WxCustomMessage reply = new WxCustomMessage(); | |||
reply.setTouser("OPENID"); | |||
reply.setMsgtype(WxMsgType.TEXT); | |||
reply.setMsgtype(WxConsts.TEXT); | |||
reply.setContent("sfsfdsdf"); | |||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"text\",\"text\":{\"content\":\"sfsfdsdf\"}}"); | |||
} | |||
@@ -20,7 +21,7 @@ public class WxCustomMessageTest { | |||
public void testImageReply() { | |||
WxCustomMessage reply = new WxCustomMessage(); | |||
reply.setTouser("OPENID"); | |||
reply.setMsgtype(WxMsgType.IMAGE); | |||
reply.setMsgtype(WxConsts.IMAGE); | |||
reply.setMedia_id("MEDIA_ID"); | |||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"image\",\"image\":{\"media_id\":\"MEDIA_ID\"}}"); | |||
} | |||
@@ -28,7 +29,7 @@ public class WxCustomMessageTest { | |||
public void testVoiceReply() { | |||
WxCustomMessage reply = new WxCustomMessage(); | |||
reply.setTouser("OPENID"); | |||
reply.setMsgtype(WxMsgType.VOICE); | |||
reply.setMsgtype(WxConsts.VOICE); | |||
reply.setMedia_id("MEDIA_ID"); | |||
Assert.assertEquals(reply.toJson(), "{\"touser\":\"OPENID\",\"msgtype\":\"voice\",\"voice\":{\"media_id\":\"MEDIA_ID\"}}"); | |||
} | |||
@@ -36,7 +37,7 @@ public class WxCustomMessageTest { | |||
public void testVideoReply() { | |||
WxCustomMessage reply = new WxCustomMessage(); | |||
reply.setTouser("OPENID"); | |||
reply.setMsgtype(WxMsgType.VIDEO); | |||
reply.setMsgtype(WxConsts.VIDEO); | |||
reply.setMedia_id("MEDIA_ID"); | |||
reply.setThumb_media_id("MEDIA_ID"); | |||
reply.setTitle("TITLE"); | |||
@@ -47,7 +48,7 @@ public class WxCustomMessageTest { | |||
public void testMusicReply() { | |||
WxCustomMessage reply = new WxCustomMessage(); | |||
reply.setTouser("OPENID"); | |||
reply.setMsgtype(WxMsgType.MUSIC); | |||
reply.setMsgtype(WxConsts.MUSIC); | |||
reply.setThumb_media_id("MEDIA_ID"); | |||
reply.setDescription("DESCRIPTION"); | |||
reply.setTitle("TITLE"); | |||
@@ -59,7 +60,7 @@ public class WxCustomMessageTest { | |||
public void testNewsReply() { | |||
WxCustomMessage reply = new WxCustomMessage(); | |||
reply.setTouser("OPENID"); | |||
reply.setMsgtype(WxMsgType.NEWS); | |||
reply.setMsgtype(WxConsts.NEWS); | |||
WxArticle article1 = new WxArticle(); | |||
article1.setUrl("URL"); |
@@ -1,9 +1,9 @@ | |||
package chanjarster.weixin.in; | |||
package chanjarster.weixin.bean; | |||
import org.testng.Assert; | |||
import org.testng.annotations.Test; | |||
import chanjarster.weixin.in.WxError; | |||
import chanjarster.weixin.bean.WxError; | |||
@Test | |||
public class WxErrorTest { |
@@ -0,0 +1,104 @@ | |||
package chanjarster.weixin.bean; | |||
import org.apache.http.util.Asserts; | |||
import org.testng.Assert; | |||
import org.testng.annotations.DataProvider; | |||
import org.testng.annotations.Test; | |||
import chanjarster.weixin.bean.WxMenu.WxMenuButton; | |||
@Test | |||
public class WxMenuTest { | |||
@Test(dataProvider="json") | |||
public void testFromJson(String json) { | |||
WxMenu menu = WxMenu.fromJson(json); | |||
Assert.assertEquals(menu.getButton().size(), 3); | |||
} | |||
@Test(dataProvider="json") | |||
public void testToJson(String json) { | |||
WxMenu menu = new WxMenu(); | |||
WxMenuButton button1 = new WxMenuButton(); | |||
button1.setType("click"); | |||
button1.setName("今日歌曲"); | |||
button1.setKey("V1001_TODAY_MUSIC"); | |||
WxMenuButton button2 = new WxMenuButton(); | |||
button2.setType("click"); | |||
button2.setName("歌手简介"); | |||
button2.setKey("V1001_TODAY_SINGER"); | |||
WxMenuButton button3 = new WxMenuButton(); | |||
button3.setName("菜单"); | |||
menu.getButton().add(button1); | |||
menu.getButton().add(button2); | |||
menu.getButton().add(button3); | |||
WxMenuButton button31 = new WxMenuButton(); | |||
button31.setType("view"); | |||
button31.setName("搜索"); | |||
button31.setUrl("http://www.soso.com/"); | |||
WxMenuButton button32 = new WxMenuButton(); | |||
button32.setType("view"); | |||
button32.setName("视频"); | |||
button32.setUrl("http://v.qq.com/"); | |||
WxMenuButton button33 = new WxMenuButton(); | |||
button33.setType("click"); | |||
button33.setName("赞一下我们"); | |||
button33.setKey("V1001_GOOD"); | |||
button3.getSub_button().add(button31); | |||
button3.getSub_button().add(button32); | |||
button3.getSub_button().add(button33); | |||
System.out.println(menu.toJson()); | |||
Assert.assertEquals(menu.toJson(), json); | |||
} | |||
@DataProvider(name="json") | |||
public Object[][] getMenuJson() { | |||
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\"" | |||
+"}" | |||
+"]" | |||
+"}" | |||
+"]" | |||
+"}"; | |||
return new Object[][] { | |||
new Object[] { json } | |||
}; | |||
} | |||
} |
@@ -1,13 +1,13 @@ | |||
package chanjarster.weixin.out; | |||
package chanjarster.weixin.bean; | |||
import org.testng.Assert; | |||
import org.testng.annotations.Test; | |||
import chanjarster.weixin.out.WxUserMessage; | |||
import chanjarster.weixin.service.WxMsgType; | |||
import chanjarster.weixin.api.WxConsts; | |||
import chanjarster.weixin.bean.WxXmlMessage; | |||
@Test | |||
public class WxUserMessageTest { | |||
public class WxXmlMessageTest { | |||
public void testFromXml() { | |||
@@ -36,11 +36,11 @@ public class WxUserMessageTest { | |||
+ "<Longitude>113.352425</Longitude>" | |||
+ "<Precision>119.385040</Precision>" | |||
+ "</xml>"; | |||
WxUserMessage wxMessage = WxUserMessage.fromXml(xml); | |||
WxXmlMessage wxMessage = WxXmlMessage.fromXml(xml); | |||
Assert.assertEquals(wxMessage.getToUserName(), "toUser"); | |||
Assert.assertEquals(wxMessage.getFromUserName(), "fromUser"); | |||
Assert.assertEquals(wxMessage.getCreateTime(), new Long(1348831860l)); | |||
Assert.assertEquals(wxMessage.getMsgType(), WxMsgType.TEXT); | |||
Assert.assertEquals(wxMessage.getMsgType(), WxConsts.TEXT); | |||
Assert.assertEquals(wxMessage.getContent(), "this is a test"); | |||
Assert.assertEquals(wxMessage.getMsgId(), new Long(1234567890123456l)); | |||
Assert.assertEquals(wxMessage.getPicUrl(), "this is a url"); | |||
@@ -63,11 +63,11 @@ public class WxUserMessageTest { | |||
} | |||
public void testToXml() { | |||
WxUserMessage wxMessage = new WxUserMessage(); | |||
WxXmlMessage wxMessage = new WxXmlMessage(); | |||
wxMessage.setToUserName("toUser"); | |||
wxMessage.setFromUserName("fromUser"); | |||
wxMessage.setCreateTime(new Long(1348831860l)); | |||
wxMessage.setMsgType(WxMsgType.TEXT); | |||
wxMessage.setMsgType(WxConsts.TEXT); | |||
wxMessage.setContent("this is a test"); | |||
wxMessage.setMsgId(new Long(1234567890123456l)); | |||
wxMessage.setPicUrl("this is a url"); |