| @@ -3,7 +3,7 @@ package chanjarster.weixin.api; | |||
| import chanjarster.weixin.bean.WxAccessToken; | |||
| /** | |||
| * 微信配置的工具类 | |||
| * 微信客户端配置存储 | |||
| * @author chanjarster | |||
| * | |||
| */ | |||
| @@ -5,13 +5,14 @@ import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import chanjarster.weixin.bean.WxCustomMessage; | |||
| import chanjarster.weixin.bean.WxGroup; | |||
| import chanjarster.weixin.bean.WxMassGroupMessage; | |||
| import chanjarster.weixin.bean.WxMassNews; | |||
| import chanjarster.weixin.bean.WxMassOpenIdsMessage; | |||
| import chanjarster.weixin.bean.WxMassVideo; | |||
| import chanjarster.weixin.bean.WxMenu; | |||
| import chanjarster.weixin.bean.result.WxMassUploadResult; | |||
| import chanjarster.weixin.bean.result.WxMassSendResult; | |||
| import chanjarster.weixin.bean.result.WxMassUploadResult; | |||
| import chanjarster.weixin.bean.result.WxMediaUploadResult; | |||
| import chanjarster.weixin.exception.WxErrorException; | |||
| @@ -176,5 +177,19 @@ public interface WxService { | |||
| */ | |||
| public WxMenu menuGet() throws WxErrorException; | |||
| /** | |||
| * <pre> | |||
| * 分组管理接口 - 创建分组 | |||
| * 详情请见: http://mp.weixin.qq.com/wiki/index.php?title=分组管理接口 | |||
| * </pre> | |||
| * @param name 分组名字(30个字符以内) | |||
| * @throws WxErrorException | |||
| */ | |||
| public WxGroup groupCreate(String name) throws WxErrorException; | |||
| /** | |||
| * 注入 {@link WxConfigStorage} 的实现 | |||
| * @param wxConfigProvider | |||
| */ | |||
| public void setWxConfigStorage(WxConfigStorage wxConfigProvider); | |||
| } | |||
| @@ -4,6 +4,7 @@ import java.io.File; | |||
| import java.io.IOException; | |||
| import java.io.InputStream; | |||
| import java.security.MessageDigest; | |||
| import java.text.MessageFormat; | |||
| import java.util.Arrays; | |||
| import java.util.UUID; | |||
| import java.util.concurrent.atomic.AtomicBoolean; | |||
| @@ -18,6 +19,7 @@ import org.apache.http.impl.client.HttpClients; | |||
| import chanjarster.weixin.bean.WxAccessToken; | |||
| import chanjarster.weixin.bean.WxCustomMessage; | |||
| import chanjarster.weixin.bean.WxGroup; | |||
| import chanjarster.weixin.bean.WxMassGroupMessage; | |||
| import chanjarster.weixin.bean.WxMassNews; | |||
| import chanjarster.weixin.bean.WxMassOpenIdsMessage; | |||
| @@ -183,6 +185,12 @@ public class WxServiceImpl implements WxService { | |||
| return WxMassSendResult.fromJson(responseContent); | |||
| } | |||
| public WxGroup groupCreate(String name) throws WxErrorException { | |||
| String url = "https://api.weixin.qq.com/cgi-bin/groups/create"; | |||
| String responseContent = execute(new SimplePostRequestExecutor(), url, MessageFormat.format("'{'\"group\":'{'\"name\":\"{0}\"}}", name)); | |||
| return WxGroup.fromJson(responseContent); | |||
| } | |||
| /** | |||
| * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | |||
| * @param executor | |||
| @@ -13,16 +13,16 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| */ | |||
| public class WxCustomMessage { | |||
| protected String touser; | |||
| protected String msgtype; | |||
| protected String content; | |||
| protected String media_id; | |||
| protected String thumb_media_id; | |||
| protected String title; | |||
| protected String description; | |||
| protected String musicurl; | |||
| protected String hqmusicurl; | |||
| protected List<WxArticle> articles = new ArrayList<WxArticle>(); | |||
| private String touser; | |||
| private String msgtype; | |||
| private String content; | |||
| private String media_id; | |||
| private String thumb_media_id; | |||
| private String title; | |||
| private String description; | |||
| private String musicurl; | |||
| private String hqmusicurl; | |||
| private List<WxArticle> articles = new ArrayList<WxArticle>(); | |||
| public String getTouser() { | |||
| return touser; | |||
| @@ -104,10 +104,10 @@ public class WxCustomMessage { | |||
| public static class WxArticle { | |||
| protected String title; | |||
| protected String description; | |||
| protected String url; | |||
| protected String picurl; | |||
| private String title; | |||
| private String description; | |||
| private String url; | |||
| private String picurl; | |||
| public String getTitle() { | |||
| return title; | |||
| @@ -0,0 +1,42 @@ | |||
| package chanjarster.weixin.bean; | |||
| import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| /** | |||
| * 微信用户分组 | |||
| * @author chanjarster | |||
| * | |||
| */ | |||
| public class WxGroup { | |||
| private long id; | |||
| private String name; | |||
| private long count; | |||
| public long getId() { | |||
| return id; | |||
| } | |||
| public void setId(long id) { | |||
| this.id = id; | |||
| } | |||
| public String getName() { | |||
| return name; | |||
| } | |||
| public void setName(String name) { | |||
| this.name = name; | |||
| } | |||
| public long getCount() { | |||
| return count; | |||
| } | |||
| public void setCount(long count) { | |||
| this.count = count; | |||
| } | |||
| public static WxGroup fromJson(String json) { | |||
| return WxGsonBuilder.create().fromJson(json, WxGroup.class); | |||
| } | |||
| public String toJson(String json) { | |||
| return WxGsonBuilder.create().toJson(this); | |||
| } | |||
| } | |||
| @@ -10,10 +10,10 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| */ | |||
| public class WxMassGroupMessage { | |||
| protected String group_id; | |||
| protected String msgtype; | |||
| protected String content; | |||
| protected String media_id; | |||
| private String group_id; | |||
| private String msgtype; | |||
| private String content; | |||
| private String media_id; | |||
| public WxMassGroupMessage() { | |||
| super(); | |||
| @@ -12,7 +12,7 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| */ | |||
| public class WxMassNews { | |||
| protected List<WxMassNewsArticle> articles = new ArrayList<WxMassNewsArticle>(); | |||
| private List<WxMassNewsArticle> articles = new ArrayList<WxMassNewsArticle>(); | |||
| public List<WxMassNewsArticle> getArticles() { | |||
| return articles; | |||
| @@ -44,31 +44,31 @@ public class WxMassNews { | |||
| /** | |||
| * (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得 | |||
| */ | |||
| protected String thumb_media_id; | |||
| private String thumb_media_id; | |||
| /** | |||
| * 图文消息的作者 | |||
| */ | |||
| protected String author; | |||
| private String author; | |||
| /** | |||
| * (必填) 图文消息的标题 | |||
| */ | |||
| protected String title; | |||
| private String title; | |||
| /** | |||
| * 在图文消息页面点击“阅读原文”后的页面链接 | |||
| */ | |||
| protected String content_source_url; | |||
| private String content_source_url; | |||
| /** | |||
| * (必填) 图文消息页面的内容,支持HTML标签 | |||
| */ | |||
| protected String content; | |||
| private String content; | |||
| /** | |||
| * 图文消息的描述 | |||
| */ | |||
| protected String digest; | |||
| private String digest; | |||
| /** | |||
| * 是否显示封面,true为显示,false为不显示 | |||
| */ | |||
| protected boolean show_cover_pic; | |||
| private boolean show_cover_pic; | |||
| public String getThumb_media_id() { | |||
| return thumb_media_id; | |||
| @@ -13,10 +13,10 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| */ | |||
| public class WxMassOpenIdsMessage { | |||
| protected List<String> touser = new ArrayList<String>(); | |||
| protected String msgtype; | |||
| protected String content; | |||
| protected String media_id; | |||
| private List<String> touser = new ArrayList<String>(); | |||
| private String msgtype; | |||
| private String content; | |||
| private String media_id; | |||
| public WxMassOpenIdsMessage() { | |||
| super(); | |||
| @@ -9,9 +9,9 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| */ | |||
| public class WxMassVideo { | |||
| protected String media_id; | |||
| protected String title; | |||
| protected String description; | |||
| private String media_id; | |||
| private String title; | |||
| private String description; | |||
| public String getTitle() { | |||
| return title; | |||
| @@ -14,7 +14,7 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| */ | |||
| public class WxMenu { | |||
| protected List<WxMenuButton> button = new ArrayList<WxMenuButton>(); | |||
| private List<WxMenuButton> button = new ArrayList<WxMenuButton>(); | |||
| public List<WxMenuButton> getButton() { | |||
| return button; | |||
| @@ -38,12 +38,12 @@ public class WxMenu { | |||
| public static class WxMenuButton { | |||
| protected String type; | |||
| protected String name; | |||
| protected String key; | |||
| protected String url; | |||
| private String type; | |||
| private String name; | |||
| private String key; | |||
| private String url; | |||
| protected List<WxMenuButton> sub_button = new ArrayList<WxMenuButton>(); | |||
| private List<WxMenuButton> sub_button = new ArrayList<WxMenuButton>(); | |||
| public String getType() { | |||
| return type; | |||
| @@ -15,9 +15,9 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| */ | |||
| public class WxMassSendResult { | |||
| protected String errcode; | |||
| protected String errmsg; | |||
| protected String msg_id; | |||
| private String errcode; | |||
| private String errmsg; | |||
| private String msg_id; | |||
| public String getErrcode() { | |||
| return errcode; | |||
| @@ -12,9 +12,9 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| */ | |||
| public class WxMassUploadResult { | |||
| protected String type; | |||
| protected String media_id; | |||
| protected long created_at; | |||
| private String type; | |||
| private String media_id; | |||
| private long created_at; | |||
| public String getType() { | |||
| return type; | |||
| @@ -4,10 +4,10 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||
| public class WxMediaUploadResult { | |||
| protected String type; | |||
| protected String media_id; | |||
| protected String thumb_media_id; | |||
| protected long created_at; | |||
| private String type; | |||
| private String media_id; | |||
| private String thumb_media_id; | |||
| private long created_at; | |||
| public String getType() { | |||
| return type; | |||
| @@ -0,0 +1,55 @@ | |||
| /* | |||
| * 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.json; | |||
| import java.lang.reflect.Type; | |||
| import chanjarster.weixin.bean.WxGroup; | |||
| 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; | |||
| /** | |||
| * | |||
| * @author qianjia | |||
| * | |||
| */ | |||
| public class WxGroupGsonAdapter implements JsonSerializer<WxGroup>, JsonDeserializer<WxGroup> { | |||
| public JsonElement serialize(WxGroup group, Type typeOfSrc, JsonSerializationContext context) { | |||
| JsonObject json = new JsonObject(); | |||
| JsonObject groupJson = new JsonObject(); | |||
| groupJson.addProperty("name", group.getName()); | |||
| groupJson.addProperty("id", group.getId()); | |||
| groupJson.addProperty("count", group.getCount()); | |||
| json.add("group", groupJson); | |||
| return json; | |||
| } | |||
| public WxGroup deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { | |||
| WxGroup group = new WxGroup(); | |||
| JsonObject groupJson = json.getAsJsonObject().get("group").getAsJsonObject(); | |||
| if (groupJson.get("name") != null && !groupJson.get("name").isJsonNull()) { | |||
| group.setName(GsonHelper.getAsString(groupJson.get("name"))); | |||
| } | |||
| if (groupJson.get("id") != null && !groupJson.get("id").isJsonNull()) { | |||
| group.setId(GsonHelper.getAsPrimitiveLong(groupJson.get("id"))); | |||
| } | |||
| if (groupJson.get("count") != null && !groupJson.get("count").isJsonNull()) { | |||
| group.setCount(GsonHelper.getAsPrimitiveLong(groupJson.get("count"))); | |||
| } | |||
| return group; | |||
| } | |||
| } | |||
| @@ -1,6 +1,7 @@ | |||
| package chanjarster.weixin.util.json; | |||
| import chanjarster.weixin.bean.WxCustomMessage; | |||
| import chanjarster.weixin.bean.WxGroup; | |||
| import chanjarster.weixin.bean.WxMassGroupMessage; | |||
| import chanjarster.weixin.bean.WxMassNews; | |||
| import chanjarster.weixin.bean.WxMassOpenIdsMessage; | |||
| @@ -20,6 +21,8 @@ public class WxGsonBuilder { | |||
| INSTANCE.registerTypeAdapter(WxMassNews.class, new WxMassNewsGsonAdapter()); | |||
| INSTANCE.registerTypeAdapter(WxMassGroupMessage.class, new WxMassMessageGsonAdapter()); | |||
| INSTANCE.registerTypeAdapter(WxMassOpenIdsMessage.class, new WxMassOpenIdsMessageGsonAdapter()); | |||
| INSTANCE.registerTypeAdapter(WxGroup.class, new WxGroupGsonAdapter()); | |||
| } | |||
| public static Gson create() { | |||
| @@ -0,0 +1,29 @@ | |||
| package chanjarster.weixin.api; | |||
| import org.testng.Assert; | |||
| import org.testng.annotations.Guice; | |||
| import org.testng.annotations.Test; | |||
| import chanjarster.weixin.bean.WxGroup; | |||
| import chanjarster.weixin.exception.WxErrorException; | |||
| import com.google.inject.Inject; | |||
| /** | |||
| * 测试分组接口 | |||
| * | |||
| * @author chanjarster | |||
| */ | |||
| @Test(groups = "groupAPI", dependsOnGroups = "baseAPI") | |||
| @Guice(modules = ApiTestModule.class) | |||
| public class WxGroupAPITest { | |||
| @Inject | |||
| protected WxServiceImpl wxService; | |||
| public void testCreateMenu() throws WxErrorException { | |||
| WxGroup res = wxService.groupCreate("测试分组1"); | |||
| Assert.assertEquals(res.getName(), "测试分组1"); | |||
| } | |||
| } | |||
| @@ -18,7 +18,7 @@ import chanjarster.weixin.exception.WxErrorException; | |||
| * @author chanjarster | |||
| * | |||
| */ | |||
| @Test(dependsOnGroups="baseAPI") | |||
| @Test(groups="menuAPI", dependsOnGroups="baseAPI") | |||
| @Guice(modules = ApiTestModule.class) | |||
| public class WxMenuAPITest { | |||