diff --git a/CHANGE.md b/CHANGE.md index 79c406a9..02fa63ae 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -609,4 +609,8 @@ + weixin4j-[mp|qy]:version upgrade to 1.6.6 - + weixin4j-server:version upgrade to 1.1.5 \ No newline at end of file + + weixin4j-server:version upgrade to 1.1.5 + +* 2016-01-20 + + + weixin4j-mp:新增获取模板和删除模板接口 \ No newline at end of file diff --git a/weixin4j-mp/CHANGE.md b/weixin4j-mp/CHANGE.md index 7aeacd45..ac1ea170 100644 --- a/weixin4j-mp/CHANGE.md +++ b/weixin4j-mp/CHANGE.md @@ -198,4 +198,8 @@ * 2015-12-31 - + version upgrade to 1.6.6 \ No newline at end of file + + version upgrade to 1.6.6 + +* 2016-01-20 + + + 新增获取模板和删除模板接口 \ No newline at end of file diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index 1d8ef4f0..364e97ed 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -40,6 +40,7 @@ import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRResult; import com.foxinmy.weixin4j.mp.model.SemQuery; import com.foxinmy.weixin4j.mp.model.SemResult; +import com.foxinmy.weixin4j.mp.model.TemplateMessageInfo; import com.foxinmy.weixin4j.mp.model.User; import com.foxinmy.weixin4j.mp.token.WeixinTicketCreator; import com.foxinmy.weixin4j.mp.token.WeixinTokenCreator; @@ -1224,7 +1225,7 @@ public class WeixinProxy { /** * 设置所属行业(每月可修改行业1次,账号仅可使用所属行业中相关的模板) * - * @param industryType + * @param industryTypes * 所处行业 目前不超过两个 * @return 操作结果 * @throws WeixinException @@ -1233,9 +1234,9 @@ public class WeixinProxy { * @see 设置所处行业 */ - public JsonResult setTmplIndustry(IndustryType... industryType) + public JsonResult setTmplIndustry(IndustryType... industryTypes) throws WeixinException { - return tmplApi.setTmplIndustry(industryType); + return tmplApi.setTmplIndustry(industryTypes); } /** @@ -1253,6 +1254,35 @@ public class WeixinProxy { return tmplApi.getTemplateId(shortId); } + /** + * 获取模板列表 + * + * @return 模板列表 + * @see com.foxinmy.weixin4j.mp.model.TemplateMessageInfo + * @see 获取模板列表 + * @see com.foxinmy.weixin4j.mp.api.TmplApi + * @throws WeixinException + */ + public List getAllTemplates() throws WeixinException { + return tmplApi.getAllTemplates(); + } + + /** + * 删除模板 + * + * @param templateId + * 公众帐号下模板消息ID + * @return 处理结果 + * @see 删除模板 + * @see com.foxinmy.weixin4j.mp.api.TmplApi + * @throws WeixinException + */ + public JsonResult deleteTemplate(String templateId) throws WeixinException { + return tmplApi.deleteTemplate(templateId); + } + /** * 发送模板消息 * diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TmplApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TmplApi.java index 09918ea5..39e8d98e 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TmplApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/TmplApi.java @@ -1,14 +1,19 @@ package com.foxinmy.weixin4j.mp.api; +import java.util.List; + import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; +import com.alibaba.fastjson.serializer.NameFilter; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.mp.message.TemplateMessage; +import com.foxinmy.weixin4j.mp.model.TemplateMessageInfo; import com.foxinmy.weixin4j.mp.type.IndustryType; import com.foxinmy.weixin4j.token.TokenHolder; +import com.foxinmy.weixin4j.util.NameValue; /** * 模板消息相关API @@ -30,20 +35,20 @@ public class TmplApi extends MpApi { /** * 设置所属行业(每月可修改行业1次,账号仅可使用所属行业中相关的模板) * - * @param industryType + * @param industryTypes * 所处行业 目前不超过两个 * @return 操作结果 * @throws WeixinException * @see com.foxinmy.weixin4j.mp.type.IndustryType * @see 设置所处行业 + * href="http://mp.weixin.qq.com/wiki/5/6dde9eaa909f83354e0094dc3ad99e05.html#.E8.AE.BE.E7.BD.AE.E6.89.80.E5.B1.9E.E8.A1.8C.E4.B8.9A">设置所处行业 */ - public JsonResult setTmplIndustry(IndustryType... industryType) + public JsonResult setTmplIndustry(IndustryType... industryTypes) throws WeixinException { JSONObject obj = new JSONObject(); - for (int i = 0; i < industryType.length; i++) { + for (int i = 0; i < industryTypes.length; i++) { obj.put(String.format("industry_id%d", i + 1), - String.valueOf(industryType[i].getValue())); + Integer.toString(industryTypes[i].getTypeId())); } Token token = tokenHolder.getToken(); String template_set_industry_uri = getRequestUri("template_set_industry_uri"); @@ -54,6 +59,32 @@ public class TmplApi extends MpApi { return response.getAsJsonResult(); } + /** + * 获取设置的行业信息 + * + * @return 行业信息数组 第一个元素为帐号设置的主营行业 第二个元素为帐号设置的副营行业 + * @throws WeixinException + * @see com.foxinmy.weixin4j.mp.type.IndustryType + * @see 获取设置的行业信息 + */ + public IndustryType[] getTmplIndustry() throws WeixinException { + String template_get_industry_uri = getRequestUri("template_get_industry_uri"); + WeixinResponse response = weixinExecutor.get(String.format( + template_get_industry_uri, tokenHolder.getAccessToken())); + JSONObject primary = response.getAsJson().getJSONObject( + "primary_industry"); + JSONObject secondary = response.getAsJson().getJSONObject( + "secondary_industry"); + return new IndustryType[] { + primary != null ? IndustryType.getIndustry( + primary.getString("first_class"), + primary.getString("second_class")) : null, + secondary != null ? IndustryType.getIndustry( + secondary.getString("first_class"), + secondary.getString("second_class")) : null }; + } + /** * 获取模板ID * @@ -62,7 +93,7 @@ public class TmplApi extends MpApi { * @return 模板ID * @throws WeixinException * @see 获得模板ID + * href="http://mp.weixin.qq.com/wiki/5/6dde9eaa909f83354e0094dc3ad99e05.html#.E8.8E.B7.E5.BE.97.E6.A8.A1.E6.9D.BFID">获得模板ID */ public String getTemplateId(String shortId) throws WeixinException { Token token = tokenHolder.getToken(); @@ -74,6 +105,43 @@ public class TmplApi extends MpApi { return response.getAsJson().getString("template_id"); } + /** + * 获取模板列表 + * + * @return 模板列表 + * @see com.foxinmy.weixin4j.mp.model.TemplateMessageInfo + * @see 获取模板列表 + * @throws WeixinException + */ + public List getAllTemplates() throws WeixinException { + Token token = tokenHolder.getToken(); + String template_getall_uri = getRequestUri("template_getall_uri"); + WeixinResponse response = weixinExecutor.get(String.format( + template_getall_uri, token.getAccessToken())); + return JSON.parseArray(response.getAsJson().getString("template_list"), + TemplateMessageInfo.class); + } + + /** + * 删除模板 + * + * @param templateId + * 公众帐号下模板消息ID + * @return 处理结果 + * @see 删除模板 + * @throws WeixinException + */ + public JsonResult deleteTemplate(String templateId) throws WeixinException { + Token token = tokenHolder.getToken(); + String template_del_uri = getRequestUri("template_del_uri"); + WeixinResponse response = weixinExecutor.post( + String.format(template_del_uri, token.getAccessToken()), + String.format("{\"template_id\"=\"%s\"}", templateId)); + return response.getAsJsonResult(); + } + /** * 发送模板消息 * @@ -83,7 +151,7 @@ public class TmplApi extends MpApi { * @throws WeixinException * @see 模板消息 - * 运营规范 * @see com.foxinmy.weixin4j.mp.message.TemplateMessage @@ -95,7 +163,16 @@ public class TmplApi extends MpApi { String template_send_uri = getRequestUri("template_send_uri"); WeixinResponse response = weixinExecutor.post( String.format(template_send_uri, token.getAccessToken()), - JSON.toJSONString(tplMessage)); + JSON.toJSONString(tplMessage, new NameFilter() { + @Override + public String process(Object object, String name, + Object value) { + if (object instanceof NameValue && name.equals("name")) { + return "color"; + } + return name; + } + })); return response.getAsJsonResult(); } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index 841afdc6..eae20688 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -113,8 +113,14 @@ p_shorturl_uri={mch_base_url}/tools/shorturl updateremark_uri={api_cgi_url}/user/info/updateremark?access_token=%s # \u8bbe\u7f6e\u6a21\u677f\u6d88\u606f\u6240\u5904\u884c\u4e1a template_set_industry_uri={api_cgi_url}/template/api_set_industry?access_token=%s +# \u83b7\u53d6\u8bbe\u7f6e\u7684\u884c\u4e1a\u4fe1\u606f +template_get_industry_uri={api_cgi_url}/template/get_industry?access_token=%s # \u83b7\u53d6\u6a21\u677f\u6d88\u606fID template_getid_uri={api_cgi_url}/template/api_add_template?access_token=%s +# \u83b7\u53d6\u6a21\u677f\u5217\u8868 +template_getall_uri={api_cgi_url}/template/get_all_private_template?access_token=%s +# \u5220\u9664\u6a21\u677f +template_del_uri={api_cgi_url}/template/del_private_template?access_token=%s # \u53d1\u9001\u6a21\u677f\u6d88\u606f template_send_uri={api_cgi_url}/message/template/send?access_token=%s # \u8bed\u4e49\u7406\u89e3 diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/message/TemplateMessage.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/message/TemplateMessage.java index f5dbdad8..27eff59b 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/message/TemplateMessage.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/message/TemplateMessage.java @@ -6,6 +6,7 @@ import java.util.Map; import com.alibaba.fastjson.annotation.JSONCreator; import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.util.NameValue; /** * 模板消息 @@ -36,14 +37,23 @@ public class TemplateMessage implements Serializable { */ private String url; /** - * 顶部的颜色值 + * 头部信息(first第一行) */ - @JSONField(name = "topcolor") - private String topColor = "#FF0000"; + @JSONField(serialize = false) + private NameValue head; + /** + * 尾部信息(remark最后行) + */ + @JSONField(serialize = false) + private NameValue tail; /** * 数据项 */ - private Map data; + @JSONField(name = "data") + private Map content; + + private final String HEAD_KEY = "first"; + private final String TAIL_KEY = "remark"; @JSONCreator public TemplateMessage(@JSONField(name = "toUser") String toUser, @@ -53,52 +63,7 @@ public class TemplateMessage implements Serializable { this.toUser = toUser; this.templateId = templateId; this.url = url; - this.topColor = "#FF0000"; - this.data = new HashMap(); - pushData("first", title); - } - - /** - * 模板消息的数据项 - * - * @className Item - * @author jy - * @date 2015年3月29日 - * @since JDK 1.6 - * @see - */ - private static class Item implements Serializable { - private static final long serialVersionUID = 1L; - /** - * 字段值 - */ - private String value; - /** - * 颜色值 - */ - private String color; - - public Item(String value) { - this(value, "#173177"); - } - - public Item(String value, String color) { - this.value = value; - this.color = color; - } - - public String getValue() { - return value; - } - - public String getColor() { - return color; - } - - @Override - public String toString() { - return "$ [value=" + getValue() + ", color=" + getColor() + "]"; - } + this.content = new HashMap(); } public String getToUser() { @@ -113,30 +78,103 @@ public class TemplateMessage implements Serializable { return url; } - public String getTopColor() { - return topColor; + public NameValue getHead() { + return head == null ? content.get(HEAD_KEY) : head; } - public void setTopColor(String topColor) { - this.topColor = topColor; + public NameValue getTail() { + return tail == null ? content.get(TAIL_KEY) : tail; } - public Map getData() { - return data; + public Map getContent() { + return content; } - public void setData(Map data) { - this.data = data; + /** + * 新增头部字段(默认颜色为#FF0000) + * + * @param text + * 字段文本 + * @return + */ + public TemplateMessage pushHead(String text) { + return pushHead("#FF0000", text); } - public void pushData(String key, String value) { - this.data.put(key, new Item(value)); + /** + * 新增头部字段 + * + * @param color + * 文字颜色 + * @param text + * 字段文本 + * @return + */ + public TemplateMessage pushHead(String color, String text) { + head = new NameValue(color, text); + content.put(HEAD_KEY, head); + return this; + } + + /** + * 新增尾部字段(默认颜色为#173177) + * + * @param text + * 字段文本 + * @return + */ + public TemplateMessage pushTail(String text) { + return pushTail("#173177", text); + } + + /** + * 新增尾部字段 + * + * @param color + * 文字颜色 + * @param text + * 字段文本 + * @return + */ + public TemplateMessage pushTail(String color, String text) { + tail = new NameValue(color, text); + content.put(TAIL_KEY, tail); + return this; + } + + /** + * 新增字段项(默认颜色为#173177) + * + * @param key + * 预留的字段名 + * @param text + * 字段文本 + * @return + */ + public TemplateMessage pushItem(String key, String text) { + return pushItem(key, "#173177", text); + } + + /** + * 新增字段项 + * + * @param key + * 预留的字段名 + * @param color + * 文字颜色 + * @param text + * 字段文本 + * @return + */ + public TemplateMessage pushItem(String key, String color, String text) { + content.put(key, new NameValue(color, text)); + return this; } @Override public String toString() { return "TemplateMessage [toUser=" + toUser + ", templateId=" - + templateId + ", url=" + url + ", topColor=" + topColor - + ", data=" + data + "]"; + + templateId + ", url=" + url + ", head=" + head + ", tail=" + + tail + ", content=" + content + "]"; } } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/TemplateMessageInfo.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/TemplateMessageInfo.java new file mode 100644 index 00000000..37366a44 --- /dev/null +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/TemplateMessageInfo.java @@ -0,0 +1,108 @@ +package com.foxinmy.weixin4j.mp.model; + +import java.io.Serializable; + +import com.alibaba.fastjson.annotation.JSONField; +import com.foxinmy.weixin4j.mp.type.IndustryType; + +/** + * 模板消息的内容 + * + * @className TemplateMessageInfo + * @author jy + * @date 2016年1月20日 + * @since JDK 1.6 + * @see + */ +public class TemplateMessageInfo implements Serializable { + + private static final long serialVersionUID = 2130414666704670905L; + + /** + * 模板ID + */ + @JSONField(name = "template_id") + private String templateId; + /** + * 模板标题 + */ + private String title; + /** + * 模板所属行业的一级行业 + */ + @JSONField(name = "primary_industry") + private String primaryIndustry; + /** + * 模板所属行业的二级行业 + */ + @JSONField(name = "deputy_industry") + private String secondaryIndustry; + /** + * 模板内容 + */ + private String content; + /** + * 模板示例 + */ + private String example; + + public String getTemplateId() { + return templateId; + } + + public void setTemplateId(String templateId) { + this.templateId = templateId; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getPrimaryIndustry() { + return primaryIndustry; + } + + public void setPrimaryIndustry(String primaryIndustry) { + this.primaryIndustry = primaryIndustry; + } + + public String getSecondaryIndustry() { + return secondaryIndustry; + } + + public void setSecondaryIndustry(String secondaryIndustry) { + this.secondaryIndustry = secondaryIndustry; + } + + public String getContent() { + return content; + } + + public void setContent(String content) { + this.content = content; + } + + public String getExample() { + return example; + } + + public void setExample(String example) { + this.example = example; + } + + public IndustryType getIndustryType() { + return IndustryType.getIndustry(primaryIndustry, secondaryIndustry); + } + + @Override + public String toString() { + return "TemplateMessageInfo [templateId=" + templateId + ", title=" + + title + ", primaryIndustry=" + primaryIndustry + + ", secondaryIndustry=" + secondaryIndustry + ", content=" + + content + ", example=" + example + "]"; + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/IndustryType.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/IndustryType.java index 31cff0f1..db606f4e 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/IndustryType.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/type/IndustryType.java @@ -1,5 +1,8 @@ package com.foxinmy.weixin4j.mp.type; +import java.util.HashMap; +import java.util.Map; + /** * 模板消息所用到的行业信息 * @@ -36,24 +39,42 @@ public enum IndustryType { "商业服务", "审计", 36), WENTIYULE_CHUANMEI("文体娱乐", "传媒", 37), WENTIYULE_TIYU( "文体娱乐", "体育", 38), WENTIYULE_YULEXIUXIAN("文体娱乐", "娱乐休闲", 39), YINSHUA_YINSHUA( "印刷", "印刷", 40), QITA_QITA("其它", "其它", 41); - private String main; - private String sub; - private int value; - IndustryType(String main, String sub, int value) { + private String primary; + private String secondary; + private int typeId; - this.value = value; + IndustryType(String primary, String secondary, int typeId) { + this.primary = primary; + this.secondary = secondary; + this.typeId = typeId; } - public String getMain() { - return main; + public String getPrimary() { + return primary; } - public String getSub() { - return sub; + public String getSecondary() { + return secondary; } - public int getValue() { - return value; + public int getTypeId() { + return typeId; + } + + private static final Map INDUSTRYTYPEMAP; + private static final String SEPARATOR; + static { + SEPARATOR = "-"; + INDUSTRYTYPEMAP = new HashMap(); + for (IndustryType type : IndustryType.values()) { + INDUSTRYTYPEMAP.put( + String.format("%s%s%s", type.getPrimary(), SEPARATOR, + type.getSecondary()), type); + } + } + public static IndustryType getIndustry(String primary, String secondary) { + return INDUSTRYTYPEMAP.get(String.format("%s%s%s", primary, SEPARATOR, + secondary)); } } diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TemplateTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TemplateTest.java index a3748e36..57ff4253 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TemplateTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TemplateTest.java @@ -25,15 +25,20 @@ public class TemplateTest extends TokenTest { } @Test - public void getid() throws WeixinException { + public void getId() throws WeixinException { System.out.println(tmplApi.getTemplateId("OPENTM201490080")); } + @Test + public void getAll() throws WeixinException { + System.out.println(tmplApi.getAllTemplates()); + } + @Test public void test() throws WeixinException { TemplateMessage tplMessage = new TemplateMessage("touser", "template_id", "title", "url"); - tplMessage.pushData("name", "val"); + tplMessage.pushHead("head").pushTail("tail").pushItem("key1", "text1"); JsonResult result = tmplApi.sendTmplMessage(tplMessage); Assert.assertEquals(0, result.getCode()); }