@@ -3,7 +3,7 @@ package chanjarster.weixin.api; | |||||
import chanjarster.weixin.bean.WxAccessToken; | import chanjarster.weixin.bean.WxAccessToken; | ||||
/** | /** | ||||
* 微信配置的工具类 | |||||
* 微信客户端配置存储 | |||||
* @author chanjarster | * @author chanjarster | ||||
* | * | ||||
*/ | */ | ||||
@@ -5,13 +5,14 @@ import java.io.IOException; | |||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import chanjarster.weixin.bean.WxCustomMessage; | import chanjarster.weixin.bean.WxCustomMessage; | ||||
import chanjarster.weixin.bean.WxGroup; | |||||
import chanjarster.weixin.bean.WxMassGroupMessage; | import chanjarster.weixin.bean.WxMassGroupMessage; | ||||
import chanjarster.weixin.bean.WxMassNews; | import chanjarster.weixin.bean.WxMassNews; | ||||
import chanjarster.weixin.bean.WxMassOpenIdsMessage; | import chanjarster.weixin.bean.WxMassOpenIdsMessage; | ||||
import chanjarster.weixin.bean.WxMassVideo; | import chanjarster.weixin.bean.WxMassVideo; | ||||
import chanjarster.weixin.bean.WxMenu; | import chanjarster.weixin.bean.WxMenu; | ||||
import chanjarster.weixin.bean.result.WxMassUploadResult; | |||||
import chanjarster.weixin.bean.result.WxMassSendResult; | import chanjarster.weixin.bean.result.WxMassSendResult; | ||||
import chanjarster.weixin.bean.result.WxMassUploadResult; | |||||
import chanjarster.weixin.bean.result.WxMediaUploadResult; | import chanjarster.weixin.bean.result.WxMediaUploadResult; | ||||
import chanjarster.weixin.exception.WxErrorException; | import chanjarster.weixin.exception.WxErrorException; | ||||
@@ -176,5 +177,19 @@ public interface WxService { | |||||
*/ | */ | ||||
public WxMenu menuGet() throws WxErrorException; | 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); | public void setWxConfigStorage(WxConfigStorage wxConfigProvider); | ||||
} | } |
@@ -4,6 +4,7 @@ import java.io.File; | |||||
import java.io.IOException; | import java.io.IOException; | ||||
import java.io.InputStream; | import java.io.InputStream; | ||||
import java.security.MessageDigest; | import java.security.MessageDigest; | ||||
import java.text.MessageFormat; | |||||
import java.util.Arrays; | import java.util.Arrays; | ||||
import java.util.UUID; | import java.util.UUID; | ||||
import java.util.concurrent.atomic.AtomicBoolean; | 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.WxAccessToken; | ||||
import chanjarster.weixin.bean.WxCustomMessage; | import chanjarster.weixin.bean.WxCustomMessage; | ||||
import chanjarster.weixin.bean.WxGroup; | |||||
import chanjarster.weixin.bean.WxMassGroupMessage; | import chanjarster.weixin.bean.WxMassGroupMessage; | ||||
import chanjarster.weixin.bean.WxMassNews; | import chanjarster.weixin.bean.WxMassNews; | ||||
import chanjarster.weixin.bean.WxMassOpenIdsMessage; | import chanjarster.weixin.bean.WxMassOpenIdsMessage; | ||||
@@ -183,6 +185,12 @@ public class WxServiceImpl implements WxService { | |||||
return WxMassSendResult.fromJson(responseContent); | 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过期时才去刷新,然后重新执行请求,而不是全局定时请求 | * 向微信端发送请求,在这里执行的策略是当发生access_token过期时才去刷新,然后重新执行请求,而不是全局定时请求 | ||||
* @param executor | * @param executor | ||||
@@ -13,16 +13,16 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||||
*/ | */ | ||||
public class WxCustomMessage { | 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() { | public String getTouser() { | ||||
return touser; | return touser; | ||||
@@ -104,10 +104,10 @@ public class WxCustomMessage { | |||||
public static class WxArticle { | 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() { | public String getTitle() { | ||||
return title; | 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 { | 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() { | public WxMassGroupMessage() { | ||||
super(); | super(); | ||||
@@ -12,7 +12,7 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||||
*/ | */ | ||||
public class WxMassNews { | public class WxMassNews { | ||||
protected List<WxMassNewsArticle> articles = new ArrayList<WxMassNewsArticle>(); | |||||
private List<WxMassNewsArticle> articles = new ArrayList<WxMassNewsArticle>(); | |||||
public List<WxMassNewsArticle> getArticles() { | public List<WxMassNewsArticle> getArticles() { | ||||
return articles; | return articles; | ||||
@@ -44,31 +44,31 @@ public class WxMassNews { | |||||
/** | /** | ||||
* (必填) 图文消息缩略图的media_id,可以在基础支持-上传多媒体文件接口中获得 | * (必填) 图文消息缩略图的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标签 | * (必填) 图文消息页面的内容,支持HTML标签 | ||||
*/ | */ | ||||
protected String content; | |||||
private String content; | |||||
/** | /** | ||||
* 图文消息的描述 | * 图文消息的描述 | ||||
*/ | */ | ||||
protected String digest; | |||||
private String digest; | |||||
/** | /** | ||||
* 是否显示封面,true为显示,false为不显示 | * 是否显示封面,true为显示,false为不显示 | ||||
*/ | */ | ||||
protected boolean show_cover_pic; | |||||
private boolean show_cover_pic; | |||||
public String getThumb_media_id() { | public String getThumb_media_id() { | ||||
return thumb_media_id; | return thumb_media_id; | ||||
@@ -13,10 +13,10 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||||
*/ | */ | ||||
public class WxMassOpenIdsMessage { | 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() { | public WxMassOpenIdsMessage() { | ||||
super(); | super(); | ||||
@@ -9,9 +9,9 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||||
*/ | */ | ||||
public class WxMassVideo { | 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() { | public String getTitle() { | ||||
return title; | return title; | ||||
@@ -14,7 +14,7 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||||
*/ | */ | ||||
public class WxMenu { | public class WxMenu { | ||||
protected List<WxMenuButton> button = new ArrayList<WxMenuButton>(); | |||||
private List<WxMenuButton> button = new ArrayList<WxMenuButton>(); | |||||
public List<WxMenuButton> getButton() { | public List<WxMenuButton> getButton() { | ||||
return button; | return button; | ||||
@@ -38,12 +38,12 @@ public class WxMenu { | |||||
public static class WxMenuButton { | 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() { | public String getType() { | ||||
return type; | return type; | ||||
@@ -15,9 +15,9 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||||
*/ | */ | ||||
public class WxMassSendResult { | 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() { | public String getErrcode() { | ||||
return errcode; | return errcode; | ||||
@@ -12,9 +12,9 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||||
*/ | */ | ||||
public class WxMassUploadResult { | 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() { | public String getType() { | ||||
return type; | return type; | ||||
@@ -4,10 +4,10 @@ import chanjarster.weixin.util.json.WxGsonBuilder; | |||||
public class WxMediaUploadResult { | 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() { | public String getType() { | ||||
return type; | 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; | package chanjarster.weixin.util.json; | ||||
import chanjarster.weixin.bean.WxCustomMessage; | import chanjarster.weixin.bean.WxCustomMessage; | ||||
import chanjarster.weixin.bean.WxGroup; | |||||
import chanjarster.weixin.bean.WxMassGroupMessage; | import chanjarster.weixin.bean.WxMassGroupMessage; | ||||
import chanjarster.weixin.bean.WxMassNews; | import chanjarster.weixin.bean.WxMassNews; | ||||
import chanjarster.weixin.bean.WxMassOpenIdsMessage; | import chanjarster.weixin.bean.WxMassOpenIdsMessage; | ||||
@@ -20,6 +21,8 @@ public class WxGsonBuilder { | |||||
INSTANCE.registerTypeAdapter(WxMassNews.class, new WxMassNewsGsonAdapter()); | INSTANCE.registerTypeAdapter(WxMassNews.class, new WxMassNewsGsonAdapter()); | ||||
INSTANCE.registerTypeAdapter(WxMassGroupMessage.class, new WxMassMessageGsonAdapter()); | INSTANCE.registerTypeAdapter(WxMassGroupMessage.class, new WxMassMessageGsonAdapter()); | ||||
INSTANCE.registerTypeAdapter(WxMassOpenIdsMessage.class, new WxMassOpenIdsMessageGsonAdapter()); | INSTANCE.registerTypeAdapter(WxMassOpenIdsMessage.class, new WxMassOpenIdsMessageGsonAdapter()); | ||||
INSTANCE.registerTypeAdapter(WxGroup.class, new WxGroupGsonAdapter()); | |||||
} | } | ||||
public static Gson create() { | 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 | * @author chanjarster | ||||
* | * | ||||
*/ | */ | ||||
@Test(dependsOnGroups="baseAPI") | |||||
@Test(groups="menuAPI", dependsOnGroups="baseAPI") | |||||
@Guice(modules = ApiTestModule.class) | @Guice(modules = ApiTestModule.class) | ||||
public class WxMenuAPITest { | public class WxMenuAPITest { | ||||