公众号:调整二维码参数类 & 新增自定义菜单配置、自动回复配置查询接口
This commit is contained in:
parent
b6c2fe7d63
commit
8995196b8d
@ -241,4 +241,9 @@
|
||||
+ **weixin4j-mp**: 新增用户分组批量移动、删除组别接口
|
||||
|
||||
+ **weixin4j-qy**: 新增WeixinTokenCreator与WeixinJSTicketCreator类
|
||||
|
||||
|
||||
* 2015-04-16
|
||||
|
||||
+ **weixin4j-mp**: <font color="red">调整[二维码参数](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/QRParameter.java)类</font>
|
||||
|
||||
+ **weixin4j-mp**: 新增获取[自定义菜单配置、自动回复配置](./weixin4j-mp/weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/HelperApi.java)接口
|
||||
@ -29,19 +29,25 @@ public class Button implements Serializable {
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 菜单的响应动作类型
|
||||
* 菜单类型 </br> <font color="red">
|
||||
* 公众平台官网上能够设置的菜单类型有view、text、img、photo、video、voice </font>
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.type.ButtonType
|
||||
*/
|
||||
private ButtonType type;
|
||||
private String type;
|
||||
/**
|
||||
* 菜单KEY值,用于消息接口推送,不超过128字节
|
||||
* 菜单KEY值,根据type的类型而定,用于消息接口推送,不超过128字节.
|
||||
* <p>
|
||||
* 官网上设置的自定义菜单:</br> Text:保存文字到value; Img、voice:保存mediaID到value;
|
||||
* Video:保存视频下载链接到value;</br> News:保存图文消息到news_info; View:保存链接到url。</br>
|
||||
* <p>
|
||||
* 使用API设置的自定义菜单:</br>
|
||||
* click、scancode_push、scancode_waitmsg、pic_sysphoto、pic_photo_or_album
|
||||
* 、</br> pic_weixin、location_select:保存值到key;view:保存链接到url
|
||||
* </p>
|
||||
* </p>
|
||||
*/
|
||||
private String key;
|
||||
/**
|
||||
* view类型必须 网页链接,用户点击菜单可打开链接,不超过256字节
|
||||
*/
|
||||
private String url;
|
||||
private Serializable content;
|
||||
/**
|
||||
* 二级菜单数组,个数应为1~5个
|
||||
*/
|
||||
@ -53,18 +59,18 @@ public class Button implements Serializable {
|
||||
|
||||
/**
|
||||
* 创建一个菜单
|
||||
* @param name 菜单显示的名称
|
||||
* @param value 当buttonType为view时value设置为url,否则为key.
|
||||
* @param buttonType 按钮类型
|
||||
*
|
||||
* @param name
|
||||
* 菜单显示的名称
|
||||
* @param content
|
||||
* 当buttonType为view时content设置为url,否则为key.
|
||||
* @param buttonType
|
||||
* 按钮类型
|
||||
*/
|
||||
public Button(String name, String value, ButtonType buttonType) {
|
||||
public Button(String name, String content, ButtonType buttonType) {
|
||||
this.name = name;
|
||||
this.type = buttonType;
|
||||
if (buttonType == ButtonType.view) {
|
||||
this.url = value;
|
||||
} else {
|
||||
this.key = value;
|
||||
}
|
||||
this.content = content;
|
||||
this.type = buttonType.name();
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
@ -75,28 +81,25 @@ public class Button implements Serializable {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public ButtonType getType() {
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(ButtonType type) {
|
||||
@JSONField(serialize = false, deserialize = false)
|
||||
public ButtonType getFormatType() {
|
||||
return ButtonType.valueOf(type);
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
public Serializable getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
public void setContent(Serializable content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public List<Button> getSubs() {
|
||||
@ -117,19 +120,7 @@ public class Button implements Serializable {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[Button name=").append(name);
|
||||
sb.append(" ,type=").append(type);
|
||||
sb.append(" ,key=").append(key);
|
||||
sb.append(" ,url=").append(url);
|
||||
if (subs != null && !subs.isEmpty()) {
|
||||
sb.append("{");
|
||||
for (Button sub : subs) {
|
||||
sb.append(sub.toString());
|
||||
}
|
||||
sb.append("}");
|
||||
}
|
||||
sb.append("]");
|
||||
return sb.toString();
|
||||
return "Button [name=" + name + ", type=" + type + ", content="
|
||||
+ content + ", subs=" + subs + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -54,11 +54,11 @@ public final class Consts {
|
||||
*/
|
||||
public static final String MICROPAYURL = "https://api.mch.weixin.qq.com/pay/micropay";
|
||||
/**
|
||||
* 商户平台下native支付的url
|
||||
* V2支付下natvie支付的url
|
||||
*/
|
||||
public static final String NATIVEURLV2 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&productid=%s×tamp=%s&noncestr=%s";
|
||||
/**
|
||||
* V2支付下natvie支付的url
|
||||
* 商户平台(V3)下native支付的url
|
||||
*/
|
||||
public static final String NATIVEURLV3 = "weixin://wxpay/bizpayurl?sign=%s&appid=%s&mch_id=%s&product_id=%s&time_stamp=%s&nonce_str=%s";
|
||||
}
|
||||
|
||||
@ -32,7 +32,7 @@ public class MpArticle implements Serializable {
|
||||
* 在图文消息页面点击“阅读原文”后的页面 可为空
|
||||
*/
|
||||
@JSONField(name = "content_source_url")
|
||||
private String url;
|
||||
private String sourceUrl;
|
||||
/**
|
||||
* 图文消息页面的内容,支持HTML标签 非空
|
||||
*/
|
||||
@ -46,6 +46,18 @@ public class MpArticle implements Serializable {
|
||||
*/
|
||||
@JSONField(name = "show_cover_pic")
|
||||
private String showCoverPic;
|
||||
|
||||
/**
|
||||
* 正文的URL 可为空
|
||||
*/
|
||||
@JSONField(name = "content_url")
|
||||
private String contentUrl;
|
||||
|
||||
/**
|
||||
* 封面图片的URL 可为空
|
||||
*/
|
||||
@JSONField(name = "cover_url")
|
||||
private String coverUrl;
|
||||
|
||||
public MpArticle(String thumbMediaId, String title, String content) {
|
||||
this.thumbMediaId = thumbMediaId;
|
||||
@ -81,12 +93,12 @@ public class MpArticle implements Serializable {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
public String getSourceUrl() {
|
||||
return sourceUrl;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
public void setSourceUrl(String sourceUrl) {
|
||||
this.sourceUrl = sourceUrl;
|
||||
}
|
||||
|
||||
public String getContent() {
|
||||
@ -113,16 +125,28 @@ public class MpArticle implements Serializable {
|
||||
this.showCoverPic = showCoverPic ? "1" : "0";
|
||||
}
|
||||
|
||||
public String getContentUrl() {
|
||||
return contentUrl;
|
||||
}
|
||||
|
||||
public void setContentUrl(String contentUrl) {
|
||||
this.contentUrl = contentUrl;
|
||||
}
|
||||
|
||||
public String getCoverUrl() {
|
||||
return coverUrl;
|
||||
}
|
||||
|
||||
public void setCoverUrl(String coverUrl) {
|
||||
this.coverUrl = coverUrl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append("[MpArticle thumbMediaId=").append(thumbMediaId);
|
||||
sb.append(", author=").append(author);
|
||||
sb.append(", title=").append(title);
|
||||
sb.append(", url=").append(url);
|
||||
sb.append(", content=").append(content);
|
||||
sb.append(", digest=").append(digest);
|
||||
sb.append(", showCoverPic=").append(showCoverPic).append("]");
|
||||
return sb.toString();
|
||||
return "MpArticle [thumbMediaId=" + thumbMediaId + ", author=" + author
|
||||
+ ", title=" + title + ", sourceUrl=" + sourceUrl
|
||||
+ ", content=" + content + ", digest=" + digest
|
||||
+ ", showCoverPic=" + showCoverPic + ", contentUrl="
|
||||
+ contentUrl + ", coverUrl=" + coverUrl + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -68,8 +68,8 @@ weixin4j-mp
|
||||
"token":"开放者的token",\
|
||||
"encodingAesKey":"公众号设置了加密方式且为「安全模式」时需要填入",\
|
||||
"mchId":"V3.x版本下的微信商户号",\
|
||||
"partnerId":"财付通的商户号",\
|
||||
"partnerKey":"财付通商户权限密钥Key",\
|
||||
"partnerId":"V2版本下的财付通的商户号",\
|
||||
"partnerKey":"V2版本下的财付通商户权限密钥Key",\
|
||||
"version":"针对微信支付的版本号(2,3),如果不填则按照mchId非空与否来判断",\
|
||||
"paySignKey":"微信支付中调用API的密钥"}
|
||||
|
||||
@ -216,4 +216,10 @@ weixin4j-mp
|
||||
|
||||
+ **weixin4j-mp-api**: 新增WeixinTokenCreator与WeixinJSTicketCreator类
|
||||
|
||||
+ **weixin4j-mp-api**: 新增用户分组批量移动、删除组别接口
|
||||
+ **weixin4j-mp-api**: 新增用户分组批量移动、删除组别接口
|
||||
|
||||
* 2015-04-16
|
||||
|
||||
+ **weixin4j-mp**: <font color="red">调整[二维码参数](./weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/model/QRParameter.java)类</font>
|
||||
|
||||
+ **weixin4j-mp**: 新增获取[自定义菜单配置、自动回复配置](./weixin4j-mp-api/src/main/java/com/foxinmy/weixin4j/mp/api/HelperApi.java)接口
|
||||
@ -61,8 +61,8 @@ weixin.properties说明
|
||||
"token":"开放者的token",\
|
||||
"encodingAesKey":"公众号设置了加密方式且为「安全模式」时需要填入",\
|
||||
"mchId":"V3.x版本下的微信商户号",\
|
||||
"partnerId":"财付通的商户号",\
|
||||
"partnerKey":"财付通商户权限密钥Key",\
|
||||
"partnerId":"V2版本下的财付通的商户号",\
|
||||
"partnerKey":"V2版本下的财付通商户权限密钥Key",\
|
||||
"version":"针对微信支付的版本号(2,3),如果不填则按照mchId非空与否来判断",\
|
||||
"paySignKey":"微信支付中调用API的密钥"}
|
||||
|
||||
@ -191,4 +191,10 @@ weixin.properties说明
|
||||
|
||||
+ 新增WeixinTokenCreator与WeixinJSTicketCreator类
|
||||
|
||||
+ 新增用户分组批量移动、删除组别接口
|
||||
+ 新增用户分组批量移动、删除组别接口
|
||||
|
||||
* 2015-04-16
|
||||
|
||||
+ **weixin4j-mp-api**: <font color="red">调整[二维码参数](./src/main/java/com/foxinmy/weixin4j/mp/model/QRParameter.java)类</font>
|
||||
|
||||
+ **weixin4j-mp-api**: 新增获取[自定义菜单配置、自动回复配置](./src/main/java/com/foxinmy/weixin4j/mp/api/HelperApi.java)接口
|
||||
@ -21,6 +21,7 @@ import com.foxinmy.weixin4j.mp.api.TmplApi;
|
||||
import com.foxinmy.weixin4j.mp.api.UserApi;
|
||||
import com.foxinmy.weixin4j.mp.message.NotifyMessage;
|
||||
import com.foxinmy.weixin4j.mp.message.TemplateMessage;
|
||||
import com.foxinmy.weixin4j.mp.model.AutoReplySetting;
|
||||
import com.foxinmy.weixin4j.mp.model.CustomRecord;
|
||||
import com.foxinmy.weixin4j.mp.model.Following;
|
||||
import com.foxinmy.weixin4j.mp.model.Group;
|
||||
@ -28,6 +29,7 @@ import com.foxinmy.weixin4j.mp.model.KfAccount;
|
||||
import com.foxinmy.weixin4j.mp.model.KfSession;
|
||||
import com.foxinmy.weixin4j.mp.model.MediaCounter;
|
||||
import com.foxinmy.weixin4j.mp.model.MediaRecord;
|
||||
import com.foxinmy.weixin4j.mp.model.MenuSetting;
|
||||
import com.foxinmy.weixin4j.mp.model.QRParameter;
|
||||
import com.foxinmy.weixin4j.mp.model.SemQuery;
|
||||
import com.foxinmy.weixin4j.mp.model.SemResult;
|
||||
@ -1073,25 +1075,6 @@ public class WeixinProxy {
|
||||
return qrApi.getQRData(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带参数的二维码
|
||||
*
|
||||
* @param sceneId
|
||||
* 场景值
|
||||
* @param expireSeconds
|
||||
* 过期秒数 如果小于等于0则 视为永久二维码
|
||||
* @return byte数据包
|
||||
* @throws WeixinException
|
||||
* @see com.foxinmy.weixin4j.mp.api.QrApi
|
||||
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#getQR(QRParameter)}
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">生成二维码</a>
|
||||
*/
|
||||
public byte[] getQRData(int sceneId, int expireSeconds)
|
||||
throws WeixinException {
|
||||
return qrApi.getQRData(sceneId, expireSeconds);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带参数的二维码
|
||||
* <p>
|
||||
@ -1206,6 +1189,37 @@ public class WeixinProxy {
|
||||
return helperApi.getcallbackip();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,
|
||||
* 而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
|
||||
*
|
||||
* @return 菜单集合
|
||||
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#getMenu()}
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/17/4dc4b0514fdad7a5fbbd477aa9aab5ed.html">获取自定义菜单配置</a>
|
||||
* @see com.foxinmy.weixin4j.model.Button
|
||||
* @se com.foxinmy.weixin4j.mp.model.MenuSetting
|
||||
* @see com.foxinmy.weixin4j.msg.model.MpArticle
|
||||
* @see com.foxinmy.weixin4j.mp.api.HelperApi
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public MenuSetting getMenuSetting() throws WeixinException {
|
||||
return helperApi.getMenuSetting();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取公众号当前使用的自动回复规则,包括关注后自动回复、消息自动回复(60分钟内触发一次)、关键词自动回复。
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting
|
||||
* @see com.foxinmy.weixin4j.mp.api.HelperApi
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/7/7b5789bb1262fb866d01b4b40b0efecb.html">获取自动回复规则</a>
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public AutoReplySetting getAutoReplySetting() throws WeixinException {
|
||||
return helperApi.getAutoReplySetting();
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据统计
|
||||
*
|
||||
|
||||
@ -53,7 +53,7 @@ public class CustomApi extends MpApi {
|
||||
* @param endtime
|
||||
* 查询结束时间 每次查询不能跨日查询
|
||||
* @param pagesize
|
||||
* 每页大小 每页最多拉取1000条
|
||||
* 每页大小 每页最多拉取50条
|
||||
* @param pageindex
|
||||
* 查询第几页 从1开始
|
||||
* @throws WeixinException
|
||||
|
||||
@ -1,15 +1,24 @@
|
||||
package com.foxinmy.weixin4j.mp.api;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import com.alibaba.fastjson.JSONArray;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.alibaba.fastjson.JSONPath;
|
||||
import com.alibaba.fastjson.TypeReference;
|
||||
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
|
||||
import com.alibaba.fastjson.serializer.NameFilter;
|
||||
import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.http.Response;
|
||||
import com.foxinmy.weixin4j.model.Button;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
import com.foxinmy.weixin4j.mp.model.AutoReplySetting;
|
||||
import com.foxinmy.weixin4j.mp.model.MenuSetting;
|
||||
import com.foxinmy.weixin4j.mp.model.SemQuery;
|
||||
import com.foxinmy.weixin4j.mp.model.SemResult;
|
||||
import com.foxinmy.weixin4j.msg.model.MpArticle;
|
||||
import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
|
||||
/**
|
||||
@ -90,4 +99,136 @@ public class HelperApi extends MpApi {
|
||||
return JSON.parseArray(response.getAsJson().getString("ip_list"),
|
||||
String.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,
|
||||
* 而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
|
||||
*
|
||||
* @return 菜单集合
|
||||
* @see {@link com.foxinmy.weixin4j.mp.api.MenuApi#getMenu()}
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/17/4dc4b0514fdad7a5fbbd477aa9aab5ed.html">获取自定义菜单配置</a>
|
||||
* @see com.foxinmy.weixin4j.model.Button
|
||||
* @see com.foxinmy.weixin4j.mp.model.MenuSetting
|
||||
* @see com.foxinmy.weixin4j.msg.model.MpArticle
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public MenuSetting getMenuSetting() throws WeixinException {
|
||||
String menu_get_selfmenu_uri = getRequestUri("menu_get_selfmenu_uri");
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.get(String.format(menu_get_selfmenu_uri,
|
||||
token.getAccessToken()));
|
||||
|
||||
JSONObject result = response.getAsJson();
|
||||
JSONArray buttons = result.getJSONObject("selfmenu_info").getJSONArray(
|
||||
"button");
|
||||
List<Button> _buttons = new ArrayList<Button>();
|
||||
|
||||
JSONObject buttonObj = null;
|
||||
Object subButton = null;
|
||||
for (int i = 0; i < buttons.size(); i++) {
|
||||
buttonObj = buttons.getJSONObject(i);
|
||||
subButton = buttonObj.remove("sub_button");
|
||||
if (subButton != null) {
|
||||
buttonObj.put("sub_button",
|
||||
((JSONObject) subButton).getJSONArray("list"));
|
||||
}
|
||||
Button button = JSON.parseObject(
|
||||
JSON.toJSONString(buttonObj, ArticleNameFilter.global),
|
||||
Button.class, NewsExtraProcessor.global);
|
||||
_buttons.add(button);
|
||||
}
|
||||
return new MenuSetting(result.getBooleanValue("is_menu_open"), _buttons);
|
||||
}
|
||||
|
||||
private static final class NewsExtraProcessor implements ExtraProcessor {
|
||||
private static NewsExtraProcessor global = new NewsExtraProcessor();
|
||||
|
||||
private NewsExtraProcessor() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void processExtra(Object object, String key, Object value) {
|
||||
if (key.equals("news_info")) {
|
||||
List<MpArticle> news = JSON
|
||||
.parseArray(((JSONObject) value).getString("list"),
|
||||
MpArticle.class);
|
||||
JSONPath.set(object, "$.content", news);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private static final class ArticleNameFilter implements NameFilter {
|
||||
private static final ArticleNameFilter global = new ArticleNameFilter();
|
||||
|
||||
private ArticleNameFilter() {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public String process(Object object, String name, Object value) {
|
||||
if (name.equals("url") || name.equals("key")) {
|
||||
return "content";
|
||||
}
|
||||
if (name.equals("show_cover")) {
|
||||
return "show_cover_pic";
|
||||
}
|
||||
if (name.equals("source_url")) {
|
||||
return "content_source_url";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取公众号当前使用的自动回复规则,包括关注后自动回复、消息自动回复(60分钟内触发一次)、关键词自动回复。
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/7/7b5789bb1262fb866d01b4b40b0efecb.html">获取自动回复规则</a>
|
||||
* @throws WeixinException
|
||||
*/
|
||||
public AutoReplySetting getAutoReplySetting() throws WeixinException {
|
||||
String autoreply_setting_get_uri = getRequestUri("autoreply_setting_get_uri");
|
||||
Token token = tokenHolder.getToken();
|
||||
Response response = request.get(String.format(
|
||||
autoreply_setting_get_uri, token.getAccessToken()));
|
||||
|
||||
JSONObject obj = response.getAsJson();
|
||||
AutoReplySetting replySetting = JSON.toJavaObject(obj,
|
||||
AutoReplySetting.class);
|
||||
List<AutoReplySetting.Rule> ruleList = null;
|
||||
if (obj.containsKey("keyword_autoreply_info")) {
|
||||
JSONArray keywordList = obj.getJSONObject("keyword_autoreply_info")
|
||||
.getJSONArray("list");
|
||||
ruleList = new ArrayList<AutoReplySetting.Rule>(keywordList.size());
|
||||
JSONObject keywordObj = null;
|
||||
JSONArray replyList = null;
|
||||
JSONObject replyObj = null;
|
||||
for (int i = 0; i < keywordList.size(); i++) {
|
||||
keywordObj = keywordList.getJSONObject(i);
|
||||
AutoReplySetting.Rule rule = JSON.toJavaObject(keywordObj,
|
||||
AutoReplySetting.Rule.class);
|
||||
replyList = keywordObj.getJSONArray("reply_list_info");
|
||||
List<AutoReplySetting.Entry> entryList = new ArrayList<AutoReplySetting.Entry>(
|
||||
replyList.size());
|
||||
for (int j = 0; j < replyList.size(); j++) {
|
||||
replyObj = replyList.getJSONObject(j);
|
||||
if (replyObj.getString("type").equals("news")) {
|
||||
entryList.add(JSON.parseObject(JSON.toJSONString(
|
||||
replyObj, ArticleNameFilter.global),
|
||||
AutoReplySetting.Entry.class,
|
||||
NewsExtraProcessor.global));
|
||||
} else {
|
||||
entryList.add(JSON.toJavaObject(replyObj,
|
||||
AutoReplySetting.Entry.class));
|
||||
}
|
||||
}
|
||||
rule.setReplyList(entryList);
|
||||
ruleList.add(rule);
|
||||
}
|
||||
}
|
||||
replySetting.setKeywordReplyList(ruleList);
|
||||
return replySetting;
|
||||
}
|
||||
}
|
||||
@ -4,12 +4,14 @@ 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.JsonResult;
|
||||
import com.foxinmy.weixin4j.http.Response;
|
||||
import com.foxinmy.weixin4j.model.Button;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
import com.foxinmy.weixin4j.type.ButtonType;
|
||||
|
||||
/**
|
||||
* 菜单相关API
|
||||
@ -31,7 +33,8 @@ public class MenuApi extends MpApi {
|
||||
/**
|
||||
* 自定义菜单
|
||||
*
|
||||
* @param btnList 菜单列表
|
||||
* @param btnList
|
||||
* 菜单列表
|
||||
* @throws WeixinException
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/13/43de8269be54a0a6f64413e4dfa94f39.html">创建自定义菜单</a>
|
||||
@ -44,7 +47,20 @@ public class MenuApi extends MpApi {
|
||||
obj.put("button", btnList);
|
||||
Response response = request.post(
|
||||
String.format(menu_create_uri, token.getAccessToken()),
|
||||
obj.toJSONString());
|
||||
JSON.toJSONString(obj, new NameFilter() {
|
||||
@Override
|
||||
public String process(Object object, String name,
|
||||
Object value) {
|
||||
if (object instanceof Button && name.equals("content")) {
|
||||
if (((Button) object).getFormatType() == ButtonType.view) {
|
||||
return "url";
|
||||
} else {
|
||||
return "key";
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}));
|
||||
|
||||
return response.getAsJsonResult();
|
||||
}
|
||||
@ -64,8 +80,18 @@ public class MenuApi extends MpApi {
|
||||
Response response = request.get(String.format(menu_get_uri,
|
||||
token.getAccessToken()));
|
||||
|
||||
String text = response.getAsJson().getJSONObject("menu")
|
||||
.getString("button");
|
||||
String text = JSON.toJSONString(
|
||||
response.getAsJson().getJSONObject("menu")
|
||||
.getJSONArray("button"), new NameFilter() {
|
||||
@Override
|
||||
public String process(Object object, String name,
|
||||
Object value) {
|
||||
if (name.equals("url") || name.equals("key")) {
|
||||
return "content";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
});
|
||||
return JSON.parseArray(text, Button.class);
|
||||
}
|
||||
|
||||
|
||||
@ -150,7 +150,7 @@ public class OauthApi extends MpApi {
|
||||
}
|
||||
|
||||
/**
|
||||
* oauth获取用户信息
|
||||
* oauth获取用户信息(需scope为 snsapi_userinfo)
|
||||
*
|
||||
* @param token
|
||||
* 授权票据
|
||||
|
||||
@ -9,7 +9,6 @@ import com.foxinmy.weixin4j.exception.WeixinException;
|
||||
import com.foxinmy.weixin4j.http.Response;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
import com.foxinmy.weixin4j.mp.model.QRParameter;
|
||||
import com.foxinmy.weixin4j.mp.type.QRType;
|
||||
import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
import com.foxinmy.weixin4j.util.ConfigUtil;
|
||||
|
||||
@ -46,7 +45,7 @@ public class QrApi extends MpApi {
|
||||
String qr_uri = getRequestUri("qr_ticket_uri");
|
||||
Response response = request.post(
|
||||
String.format(qr_uri, token.getAccessToken()),
|
||||
parameter.toJson());
|
||||
parameter.getContent());
|
||||
String ticket = response.getAsJson().getString("ticket");
|
||||
qr_uri = getRequestUri("qr_image_uri");
|
||||
response = request.get(String.format(qr_uri, ticket));
|
||||
@ -54,25 +53,6 @@ public class QrApi extends MpApi {
|
||||
return response.getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带参数的二维码
|
||||
*
|
||||
* @param sceneId
|
||||
* 场景值
|
||||
* @param expireSeconds
|
||||
* 过期秒数 如果小于等于0则 视为永久二维码
|
||||
* @return byte数据包
|
||||
* @throws WeixinException
|
||||
* @see {@link com.foxinmy.weixin4j.mp.api.QrApi#getQR(QRParameter)}
|
||||
* @see <a
|
||||
* href="http://mp.weixin.qq.com/wiki/18/28fc21e7ed87bec960651f0ce873ef8a.html">生成二维码</a>
|
||||
*/
|
||||
public byte[] getQRData(int sceneId, int expireSeconds)
|
||||
throws WeixinException {
|
||||
QRParameter parameter = new QRParameter(sceneId, expireSeconds);
|
||||
return getQRData(parameter);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成带参数的二维码
|
||||
* <p>
|
||||
@ -89,22 +69,22 @@ public class QrApi extends MpApi {
|
||||
*/
|
||||
public File getQR(QRParameter parameter) throws WeixinException {
|
||||
String qr_path = ConfigUtil.getValue("qr_path");
|
||||
String filename = String.format("%s_%d_%d.jpg", parameter.getQrType()
|
||||
.name(), parameter.getSceneId(), parameter.getExpireSeconds());
|
||||
String filename = String.format("%s_%s_%d.jpg", parameter.getQrType()
|
||||
.name(), parameter.getSceneValue(), parameter
|
||||
.getExpireSeconds());
|
||||
File file = new File(qr_path + File.separator + filename);
|
||||
if (parameter.getQrType() == QRType.PERMANENCE && file.exists()) {
|
||||
if (parameter.getQrType().ordinal() > 0 && file.exists()) {
|
||||
return file;
|
||||
}
|
||||
byte[] datas = getQRData(parameter);
|
||||
OutputStream os = null;
|
||||
try {
|
||||
boolean flag = file.exists() || file.createNewFile();
|
||||
if (flag) {
|
||||
if (file.createNewFile()) {
|
||||
os = new FileOutputStream(file);
|
||||
os.write(datas);
|
||||
} else {
|
||||
throw new WeixinException(String.format(
|
||||
"create file fail:%s", file.getAbsolutePath()));
|
||||
throw new WeixinException(String.format("create file fail:%s",
|
||||
file.getAbsolutePath()));
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new WeixinException(e.getMessage());
|
||||
|
||||
@ -55,6 +55,8 @@ following_uri={api_cgi_url}/user/get?access_token=%s&next_openid=%s
|
||||
menu_create_uri={api_cgi_url}/menu/create?access_token=%s
|
||||
# \u67e5\u8be2\u83dc\u5355
|
||||
menu_get_uri={api_cgi_url}/menu/get?access_token=%s
|
||||
# \u67e5\u8be2\u901a\u8fc7\u63a5\u53e3\u6216\u8005\u5728\u516c\u4f17\u5e73\u53f0\u4e0a\u8bbe\u7f6e\u7684\u83dc\u5355\u914d\u7f6e\u4fe1\u606f
|
||||
menu_get_selfmenu_uri={api_cgi_url}/get_current_selfmenu_info?access_token=%s
|
||||
# \u5220\u9664\u83dc\u5355
|
||||
menu_delete_uri={api_cgi_url}/menu/delete?access_token=%s
|
||||
# \u4e0a\u4f20\u56fe\u6587
|
||||
@ -164,6 +166,8 @@ material_media_del_uri={api_cgi_url}/material/del_material?access_token=%s
|
||||
material_media_count_uri={api_cgi_url}/material/get_materialcount?access_token=%s
|
||||
# \u83b7\u53d6\u5a92\u4f53\u7d20\u6750\u5217\u8868
|
||||
material_media_list_uri={api_cgi_url}/material/batchget_material?access_token=%s
|
||||
# \u81ea\u52a8\u56de\u590d\u89c4\u5219
|
||||
autoreply_setting_get_uri={api_cgi_url}/get_current_autoreply_info?access_token=%s
|
||||
|
||||
# \u53d1\u653e\u4ee3\u91d1\u5238
|
||||
coupon_send_uri={mch_base_url}/mmpaymkttransfers/send_coupon
|
||||
|
||||
@ -0,0 +1,260 @@
|
||||
package com.foxinmy.weixin4j.mp.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import com.alibaba.fastjson.annotation.JSONField;
|
||||
import com.foxinmy.weixin4j.mp.type.AutomatchMode;
|
||||
import com.foxinmy.weixin4j.mp.type.AutoreplyMode;
|
||||
|
||||
/**
|
||||
* 自动回复设置
|
||||
*
|
||||
* @className AutoReplySetting
|
||||
* @author jy
|
||||
* @date 2015年4月15日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class AutoReplySetting implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8164017927864497009L;
|
||||
|
||||
/**
|
||||
* 关注后自动回复是否开启
|
||||
*/
|
||||
@JSONField(name = "is_add_friend_reply_open")
|
||||
private boolean isAddFriendReplyOpen;
|
||||
/**
|
||||
* 消息自动回复是否开启
|
||||
*/
|
||||
@JSONField(name = "is_autoreply_open")
|
||||
private boolean isAutoreplyOpen;
|
||||
|
||||
/**
|
||||
* 关注后自动回复的信息
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting.Entry
|
||||
*/
|
||||
@JSONField(name = "add_friend_autoreply_info")
|
||||
private Entry addFriendReply;
|
||||
|
||||
/**
|
||||
* 默认自动回复的信息
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting.Entry
|
||||
*/
|
||||
@JSONField(name = "message_default_autoreply_info")
|
||||
private Entry defaultReply;
|
||||
|
||||
/**
|
||||
* 关键词自动回复的信息
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting.Rule
|
||||
*/
|
||||
private List<Rule> keywordReplyList;
|
||||
|
||||
public boolean isAddFriendReplyOpen() {
|
||||
return isAddFriendReplyOpen;
|
||||
}
|
||||
|
||||
public void setAddFriendReplyOpen(boolean isAddFriendReplyOpen) {
|
||||
this.isAddFriendReplyOpen = isAddFriendReplyOpen;
|
||||
}
|
||||
|
||||
public boolean isAutoreplyOpen() {
|
||||
return isAutoreplyOpen;
|
||||
}
|
||||
|
||||
public void setAutoreplyOpen(boolean isAutoreplyOpen) {
|
||||
this.isAutoreplyOpen = isAutoreplyOpen;
|
||||
}
|
||||
|
||||
public Entry getAddFriendReply() {
|
||||
return addFriendReply;
|
||||
}
|
||||
|
||||
public void setAddFriendReply(Entry addFriendReply) {
|
||||
this.addFriendReply = addFriendReply;
|
||||
}
|
||||
|
||||
public Entry getDefaultReply() {
|
||||
return defaultReply;
|
||||
}
|
||||
|
||||
public void setDefaultReply(Entry defaultReply) {
|
||||
this.defaultReply = defaultReply;
|
||||
}
|
||||
|
||||
public List<Rule> getKeywordReplyList() {
|
||||
return keywordReplyList;
|
||||
}
|
||||
|
||||
public void setKeywordReplyList(List<Rule> keywordReplyList) {
|
||||
this.keywordReplyList = keywordReplyList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AutoReplySetting [isAddFriendReplyOpen=" + isAddFriendReplyOpen
|
||||
+ ", isAutoreplyOpen=" + isAutoreplyOpen + ", addFriendReply="
|
||||
+ addFriendReply + ", defaultReply=" + defaultReply
|
||||
+ ", keywordReplyList=" + keywordReplyList + "]";
|
||||
}
|
||||
|
||||
/**
|
||||
* 关键字规则
|
||||
*
|
||||
* @className Rule
|
||||
* @author jy
|
||||
* @date 2015年4月15日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public static class Rule implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -7299903545861946025L;
|
||||
/**
|
||||
* 规则名称
|
||||
*/
|
||||
@JSONField(name = "rule_name")
|
||||
private String ruleName;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@JSONField(name = "create_time")
|
||||
private Date createTime;
|
||||
/**
|
||||
* 回复模式
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.type.AutoreplyMode
|
||||
*/
|
||||
@JSONField(name = "reply_mode")
|
||||
private AutoreplyMode replyMode;
|
||||
/**
|
||||
* 匹配的关键词列表
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting.Entry
|
||||
*/
|
||||
@JSONField(name = "keyword_list_info")
|
||||
private List<Entry> keywordList;
|
||||
/**
|
||||
* 回复的信息列表
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.model.AutoReplySetting.Entry
|
||||
*/
|
||||
@JSONField(name = "reply_list_info")
|
||||
private List<Entry> replyList;
|
||||
|
||||
public String getRuleName() {
|
||||
return ruleName;
|
||||
}
|
||||
|
||||
public void setRuleName(String ruleName) {
|
||||
this.ruleName = ruleName;
|
||||
}
|
||||
|
||||
public Date getCreateTime() {
|
||||
return createTime;
|
||||
}
|
||||
|
||||
public void setCreateTime(Date createTime) {
|
||||
this.createTime = createTime;
|
||||
}
|
||||
|
||||
public AutoreplyMode getReplyMode() {
|
||||
return replyMode;
|
||||
}
|
||||
|
||||
public void setReplyMode(AutoreplyMode replyMode) {
|
||||
this.replyMode = replyMode;
|
||||
}
|
||||
|
||||
public List<Entry> getKeywordList() {
|
||||
return keywordList;
|
||||
}
|
||||
|
||||
public void setKeywordList(List<Entry> keywordList) {
|
||||
this.keywordList = keywordList;
|
||||
}
|
||||
|
||||
public List<Entry> getReplyList() {
|
||||
return replyList;
|
||||
}
|
||||
|
||||
public void setReplyList(List<Entry> replyList) {
|
||||
this.replyList = replyList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Rule [ruleName=" + ruleName + ", createTime="
|
||||
+ createTime + ", replyMode=" + replyMode
|
||||
+ ", keywordList=" + keywordList + ", replyList="
|
||||
+ replyList + "]";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据项
|
||||
*
|
||||
* @className Entry
|
||||
* @author jy
|
||||
* @date 2015年4月15日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public static class Entry implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -187922224547974025L;
|
||||
/**
|
||||
* 自动回复的类型。关注后自动回复和消息自动回复的类型仅支持文本(text)、图片(img)、语音(voice)、视频(video),
|
||||
* 关键词自动回复则还多了图文消息(news)
|
||||
*/
|
||||
private String type;
|
||||
/**
|
||||
* 对于文本类型,content是文本内容,对于图片、语音、视频类型,content是mediaID,news是article
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.msg.model.MpArticle
|
||||
*/
|
||||
private Serializable content;
|
||||
/**
|
||||
* 匹配模式(仅但关键字列表)
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.type.AutomatchMode
|
||||
*/
|
||||
@JSONField(name = "match_mode")
|
||||
private AutomatchMode matchMode;
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public Serializable getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setContent(Serializable content) {
|
||||
this.content = content;
|
||||
}
|
||||
|
||||
public AutomatchMode getMatchMode() {
|
||||
return matchMode;
|
||||
}
|
||||
|
||||
public void setMatchMode(AutomatchMode matchMode) {
|
||||
this.matchMode = matchMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Entry [type=" + type + ", content=" + content
|
||||
+ ", matchMode=" + matchMode + "]";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,48 @@
|
||||
package com.foxinmy.weixin4j.mp.model;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import com.foxinmy.weixin4j.model.Button;
|
||||
|
||||
/**
|
||||
* 自定义菜单配置
|
||||
*
|
||||
* @className MenuSetting
|
||||
* @author jy
|
||||
* @date 2015年4月14日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public class MenuSetting implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 2461505572495855830L;
|
||||
|
||||
/**
|
||||
* 菜单是否开启
|
||||
*/
|
||||
private boolean isMenuOpen;
|
||||
/**
|
||||
* 菜单列表
|
||||
*/
|
||||
private List<Button> buttons;
|
||||
|
||||
public MenuSetting(boolean isMenuOpen, List<Button> buttons) {
|
||||
this.isMenuOpen = isMenuOpen;
|
||||
this.buttons = buttons;
|
||||
}
|
||||
|
||||
public boolean isMenuOpen() {
|
||||
return isMenuOpen;
|
||||
}
|
||||
|
||||
public List<Button> getButtons() {
|
||||
return buttons;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MenuSetting [isMenuOpen=" + isMenuOpen + ", buttons=" + buttons
|
||||
+ "]";
|
||||
}
|
||||
}
|
||||
@ -16,87 +16,104 @@ import com.foxinmy.weixin4j.mp.type.QRType;
|
||||
* @date 2014年4月8日
|
||||
* @since JDK 1.7
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.type.QRType
|
||||
*/
|
||||
public class QRParameter implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 6611187606558274253L;
|
||||
|
||||
/**
|
||||
* 该二维码有效时间,以秒为单位。 最大不超过1800。
|
||||
* 临时二维码的有效时间,以秒为单位。 最大不超过1800。
|
||||
*/
|
||||
private int expireSeconds;
|
||||
/**
|
||||
* 二维码类型,QR_SCENE为临时,QR_LIMIT_SCENE为永久
|
||||
* 二维码类型
|
||||
*
|
||||
* @see com.foxinmy.weixin4j.mp.type.QRType
|
||||
*/
|
||||
private QRType qrType;
|
||||
/**
|
||||
* 场景值ID,临时二维码时为32位非0整型,永久二维码时最大值为100000(目前参数只支持1--100000)
|
||||
* 场景值I 根据qrType参数而定
|
||||
*/
|
||||
private int sceneId;
|
||||
private String sceneValue;
|
||||
|
||||
private QRParameter() {
|
||||
}
|
||||
|
||||
public int getExpireSeconds() {
|
||||
return expireSeconds;
|
||||
}
|
||||
|
||||
public void setExpireSeconds(int expireSeconds) {
|
||||
this.expireSeconds = expireSeconds;
|
||||
}
|
||||
|
||||
public QRType getQrType() {
|
||||
return qrType;
|
||||
}
|
||||
|
||||
public void setQrType(QRType qrType) {
|
||||
this.qrType = qrType;
|
||||
public String getSceneValue() {
|
||||
return sceneValue;
|
||||
}
|
||||
|
||||
public int getSceneId() {
|
||||
return sceneId;
|
||||
private String content;
|
||||
|
||||
public String getContent() {
|
||||
return content;
|
||||
}
|
||||
|
||||
public void setSceneId(int sceneId) {
|
||||
this.sceneId = sceneId;
|
||||
/**
|
||||
* 创建临时二维码
|
||||
*
|
||||
* @param expireSeconds
|
||||
* 有效时间
|
||||
* @param sceneValue
|
||||
* 二维码的场景值
|
||||
* @return 二维码参数
|
||||
*/
|
||||
public static QRParameter createTemporary(int expireSeconds, int sceneValue) {
|
||||
QRParameter qr = new QRParameter();
|
||||
qr.qrType = QRType.QR_SCENE;
|
||||
qr.expireSeconds = expireSeconds;
|
||||
qr.sceneValue = Integer.toString(sceneValue);
|
||||
qr.content = String
|
||||
.format("{\"expire_seconds\": %s, \"action_name\": \"%s\", \"action_info\": {\"scene\": {\"scene_id\": %s}}}",
|
||||
expireSeconds, QRType.QR_SCENE.name(), sceneValue);
|
||||
return qr;
|
||||
}
|
||||
|
||||
public QRParameter(int sceneId, int expireSeconds) {
|
||||
this(sceneId, expireSeconds, QRType.TEMPORARY);
|
||||
if (expireSeconds <= 0) {
|
||||
this.qrType = QRType.PERMANENCE;
|
||||
}
|
||||
/**
|
||||
* 创建永久二维码(场景值为int)
|
||||
*
|
||||
* @param sceneValue
|
||||
* 场景值
|
||||
* @return 二维码参数
|
||||
*/
|
||||
public static QRParameter createPermanenceInt(int sceneValue) {
|
||||
QRParameter qr = new QRParameter();
|
||||
qr.qrType = QRType.QR_LIMIT_SCENE;
|
||||
qr.sceneValue = Integer.toString(sceneValue);
|
||||
qr.content = String
|
||||
.format("{\"action_name\": \"%s\", \"action_info\": {\"scene\": {\"scene_id\": %s}}}",
|
||||
QRType.QR_LIMIT_SCENE.name(), sceneValue);
|
||||
return qr;
|
||||
}
|
||||
|
||||
public QRParameter(int sceneId, int expireSeconds, QRType qrType) {
|
||||
this.expireSeconds = expireSeconds;
|
||||
this.qrType = qrType;
|
||||
this.sceneId = sceneId;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
/*
|
||||
* XStream xstream = new XStream(new JsonHierarchicalStreamDriver() {
|
||||
* public HierarchicalStreamWriter createWriter(Writer writer) { return
|
||||
* new JsonWriter(writer, JsonWriter.DROP_ROOT_MODE); } });
|
||||
* xstream.setMode(XStream.NO_REFERENCES);
|
||||
* xstream.autodetectAnnotations(true); if (this.qrType ==
|
||||
* QRType.QR_LIMIT_SCENE) { xstream.omitField(QRParameter.class,
|
||||
* "expire_seconds"); } return xstream.toXML(this);
|
||||
*/
|
||||
StringBuilder jsonBuilder = new StringBuilder("{");
|
||||
jsonBuilder.append("\"action_name\":\"").append(qrType.getName())
|
||||
.append("\"");
|
||||
if (this.qrType == QRType.TEMPORARY) {
|
||||
jsonBuilder.append(",\"expire_seconds\":").append(expireSeconds);
|
||||
}
|
||||
jsonBuilder.append(",\"action_info\":").append(
|
||||
String.format("{\"scene\": {\"scene_id\": %d}}", sceneId));
|
||||
jsonBuilder.append("}");
|
||||
return jsonBuilder.toString();
|
||||
/**
|
||||
* 创建永久二维码(场景值为string)
|
||||
*
|
||||
* @param sceneValue
|
||||
* 场景值
|
||||
* @return 二维码参数
|
||||
*/
|
||||
public static QRParameter createPermanenceStr(String sceneValue) {
|
||||
QRParameter qr = new QRParameter();
|
||||
qr.qrType = QRType.QR_LIMIT_STR_SCENE;
|
||||
qr.sceneValue = sceneValue;
|
||||
qr.content = String
|
||||
.format("{\"action_name\": \"%s\", \"action_info\": {\"scene\": {\"scene_str\": \"%s\"}}}",
|
||||
QRType.QR_LIMIT_STR_SCENE, sceneValue);
|
||||
return qr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "QRParameter [expireSeconds=" + expireSeconds + ", qrType="
|
||||
+ qrType + ", sceneId=" + sceneId + "]";
|
||||
+ qrType + ", sceneValue=" + sceneValue + "]";
|
||||
}
|
||||
}
|
||||
|
||||
@ -292,7 +292,7 @@ public class PayUtil {
|
||||
* 商户信息
|
||||
* @param productId
|
||||
* 与订单ID等价
|
||||
* @return
|
||||
* @return 支付链接
|
||||
*/
|
||||
public static String createNativePayRequestURLV2(
|
||||
WeixinMpAccount weixinAccount, String productId) {
|
||||
@ -316,7 +316,7 @@ public class PayUtil {
|
||||
* 支付配置信息
|
||||
* @param productId
|
||||
* 与订单ID等价
|
||||
* @return
|
||||
* @return 支付链接
|
||||
* @see <a href="http://pay.weixin.qq.com/wiki/doc/api/native.php">扫码支付</a>
|
||||
*/
|
||||
public static String createNativePayRequestURLV3(
|
||||
|
||||
@ -27,9 +27,12 @@ public class WeixinJSTicketCreator implements TokenCreator {
|
||||
private final HttpRequest request;
|
||||
|
||||
/**
|
||||
* <font color="red">公众平台的access_token</font>
|
||||
* jssdk
|
||||
*
|
||||
* @param appid
|
||||
* appid
|
||||
* @param weixinTokenHolder
|
||||
* <font color="red">公众平台的access_token</font>
|
||||
*/
|
||||
public WeixinJSTicketCreator(String appid, TokenHolder weixinTokenHolder) {
|
||||
this.appid = appid;
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
package com.foxinmy.weixin4j.mp.type;
|
||||
|
||||
/**
|
||||
* 自动匹配模式
|
||||
*
|
||||
* @className AutomatchMode
|
||||
* @author jy
|
||||
* @date 2015年4月15日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public enum AutomatchMode {
|
||||
/**
|
||||
* 代表消息中含有该关键词即可
|
||||
*/
|
||||
contain,
|
||||
/**
|
||||
* 表示消息内容必须和关键词严格相同
|
||||
*/
|
||||
equal
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
package com.foxinmy.weixin4j.mp.type;
|
||||
|
||||
/**
|
||||
* 自动回复模式
|
||||
*
|
||||
* @className AutoreplyMode
|
||||
* @author jy
|
||||
* @date 2015年4月15日
|
||||
* @since JDK 1.7
|
||||
* @see
|
||||
*/
|
||||
public enum AutoreplyMode {
|
||||
/**
|
||||
* 代表全部回复
|
||||
*/
|
||||
reply_all,
|
||||
/**
|
||||
* 代表随机回复其中一条
|
||||
*/
|
||||
random_one
|
||||
}
|
||||
@ -13,18 +13,13 @@ public enum QRType {
|
||||
/**
|
||||
* 临时二维码
|
||||
*/
|
||||
TEMPORARY("QR_SCENE"),
|
||||
QR_SCENE,
|
||||
/**
|
||||
* 永久二维码
|
||||
* 永久二维码(场景值为数字范围在1-100000之间)
|
||||
*/
|
||||
PERMANENCE("QR_LIMIT_SCENE");
|
||||
private String name;
|
||||
|
||||
QRType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
QR_LIMIT_SCENE,
|
||||
/**
|
||||
* 永久二维码(场景值为字符串长度在1-64之间)
|
||||
*/
|
||||
QR_LIMIT_STR_SCENE;
|
||||
}
|
||||
|
||||
@ -5,8 +5,8 @@ account={"id":"wx4ab8f8de58159a57","secret":"1d4eb0f4bf556aaed539f30ed05ca795",\
|
||||
"encodingAesKey":"\u516c\u4f17\u53f7\u8bbe\u7f6e\u4e86\u52a0\u5bc6\u65b9\u5f0f\u4e14\u4e3a\u300c\u5b89\u5168\u6a21\u5f0f\u300d\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"version":2,\
|
||||
"partnerId":"\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"partnerKey":"\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"partnerId":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"}
|
||||
|
||||
# \u4f7f\u7528FileTokenHolder\u65f6token\u7684\u5b58\u653e\u8def\u5f84
|
||||
|
||||
@ -22,4 +22,14 @@ public class HelpTest extends TokenTest {
|
||||
List<String> ipList = helperApi.getcallbackip();
|
||||
Assert.assertFalse(ipList.isEmpty());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getMenuSetting() throws WeixinException {
|
||||
System.err.println(helperApi.getMenuSetting());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAutoReplySetting() throws WeixinException {
|
||||
System.err.println(helperApi.getAutoReplySetting());
|
||||
}
|
||||
}
|
||||
|
||||
@ -75,9 +75,7 @@ public class MediaTest extends TokenTest {
|
||||
@Test
|
||||
public void uploadMaterialArticle() throws WeixinException {
|
||||
List<MpArticle> articles = new ArrayList<MpArticle>();
|
||||
articles.add(new MpArticle(
|
||||
"8790403529",
|
||||
"title", "content"));
|
||||
articles.add(new MpArticle("8790403529", "title", "content"));
|
||||
String mediaId = mediaApi.uploadMaterialArticle(articles);
|
||||
// 17385064953
|
||||
Assert.assertNotNull(mediaId);
|
||||
@ -86,43 +84,34 @@ public class MediaTest extends TokenTest {
|
||||
|
||||
@Test
|
||||
public void download2() throws WeixinException, IOException {
|
||||
File file = mediaApi
|
||||
.downloadMedia(
|
||||
"8790403529",
|
||||
MediaType.image, true);
|
||||
File file = mediaApi.downloadMedia("8790403529", MediaType.image, true);
|
||||
Assert.assertTrue(file.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void downloadArticle() throws WeixinException {
|
||||
List<MpArticle> articles = mediaApi
|
||||
.downloadArticle("17385064953");
|
||||
List<MpArticle> articles = mediaApi.downloadArticle("17385064953");
|
||||
Assert.assertTrue(articles != null && !articles.isEmpty());
|
||||
System.err.println(articles);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deleteMaterialMedia() throws WeixinException {
|
||||
JsonResult result = mediaApi
|
||||
.deleteMaterialMedia("17385064953");
|
||||
JsonResult result = mediaApi.deleteMaterialMedia("17385064953");
|
||||
System.err.println(result);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void updateMaterialArticle() throws WeixinException {
|
||||
MpArticle mpArticle = new MpArticle(
|
||||
"8790403529",
|
||||
"title", "content");
|
||||
MpArticle mpArticle = new MpArticle("8790403529", "title", "content");
|
||||
mpArticle.setAuthor("author_update");
|
||||
mpArticle.setDigest("digest_update");
|
||||
mpArticle.setShowCoverPic(false);
|
||||
mpArticle.setUrl("http://www.baidu.com");
|
||||
mpArticle.setSourceUrl("http://www.baidu.com");
|
||||
List<MpArticle> articles = new ArrayList<MpArticle>();
|
||||
articles.add(mpArticle);
|
||||
JsonResult result = mediaApi
|
||||
.updateMaterialArticle(
|
||||
"17385064953",
|
||||
0, articles);
|
||||
JsonResult result = mediaApi.updateMaterialArticle("17385064953", 0,
|
||||
articles);
|
||||
System.err.println(result);
|
||||
// 17385065153
|
||||
}
|
||||
@ -132,10 +121,11 @@ public class MediaTest extends TokenTest {
|
||||
MediaCounter counter = mediaApi.countMaterialMedia();
|
||||
System.err.println(counter);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void listMaterialMedia() throws WeixinException {
|
||||
MediaRecord mediaRecord = mediaApi.listMaterialMedia(MediaType.news, 0, 20);
|
||||
MediaRecord mediaRecord = mediaApi.listMaterialMedia(MediaType.news, 0,
|
||||
20);
|
||||
System.err.println(mediaRecord);
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,22 +35,18 @@ public class MenuTest extends TokenTest {
|
||||
public void create() throws WeixinException {
|
||||
btnList = new ArrayList<Button>();
|
||||
|
||||
Button b1 = new Button("我要订餐", "ORDERING", ButtonType.click);
|
||||
Button b1 = new Button("会员中心", "", ButtonType.click);
|
||||
b1.pushSub(new Button("我的信息", "U:INFO", ButtonType.click));
|
||||
b1.pushSub(new Button("修改信息", "U:UP:INFO", ButtonType.click));
|
||||
btnList.add(b1);
|
||||
|
||||
Button b2 = new Button("我", "", ButtonType.click);
|
||||
b2.pushSub(new Button("个人中心", "MINE", ButtonType.click));
|
||||
b2.pushSub(new Button("会员中心", "MEMRBER", ButtonType.click));
|
||||
b2.pushSub(new Button("我的积分", "SCORE", ButtonType.click));
|
||||
b2.pushSub(new Button("我的优惠券", "COUPON", ButtonType.click));
|
||||
b2.pushSub(new Button("我的订单", "MYORDER", ButtonType.click));
|
||||
Button b2 = new Button("最新兼职", "PART:NEWEST", ButtonType.click);
|
||||
btnList.add(b2);
|
||||
|
||||
Button b3 = new Button("商家功能", "", ButtonType.click);
|
||||
b3.pushSub(new Button("商家主页", "SHOPLIST", ButtonType.click));
|
||||
b3.pushSub(new Button("大转盘", "WHEEL", ButtonType.click));
|
||||
b3.pushSub(new Button("店铺区域", "SHOPAREA", ButtonType.click));
|
||||
b3.pushSub(new Button("店铺口味", "SHOPTASTE", ButtonType.click));
|
||||
Button b3 = new Button("功能", "", ButtonType.click);
|
||||
b3.pushSub(new Button("附近兼职", "PART:NEAR", ButtonType.click));
|
||||
b3.pushSub(new Button("搜索兼职", "PART:SO", ButtonType.click));
|
||||
b3.pushSub(new Button("公交查询", "BUS:SO", ButtonType.click));
|
||||
btnList.add(b3);
|
||||
|
||||
JsonResult result = menuApi.createMenu(btnList);
|
||||
|
||||
@ -29,15 +29,19 @@ public class QRTest extends TokenTest {
|
||||
|
||||
@Test
|
||||
public void temp_qr() throws WeixinException, IOException {
|
||||
QRParameter qr = new QRParameter(1200, 1200);
|
||||
File file = qrApi.getQR(qr);
|
||||
File file = qrApi.getQR(QRParameter.createTemporary(1200, 1200));
|
||||
Assert.assertTrue(file.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forever_qr() throws WeixinException, IOException {
|
||||
QRParameter qr = new QRParameter(1200, 0);
|
||||
File file = qrApi.getQR(qr);
|
||||
public void forever_qr_int() throws WeixinException, IOException {
|
||||
File file = qrApi.getQR(QRParameter.createPermanenceInt(1200));
|
||||
Assert.assertTrue(file.exists());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void forever_qr_str() throws WeixinException, IOException {
|
||||
File file = qrApi.getQR(QRParameter.createPermanenceStr("1200中文"));
|
||||
Assert.assertTrue(file.exists());
|
||||
}
|
||||
}
|
||||
|
||||
@ -30,7 +30,7 @@ weixin4j-mp-server
|
||||
"token":"开放者的token","openId":"公众号的openid 非必须",\\
|
||||
"encodingAesKey":"公众号设置了加密方式且为「安全模式」时需要填入",\\
|
||||
"mchId":"V3.x版本下的微信商户号",\\
|
||||
"partnerId":"财付通的商户号","partnerKey":"财付通商户权限密钥Key",\\
|
||||
"partnerId":"V2版本下的财付通的商户号","partnerKey":"V2版本下的财付通商户权限密钥Key",\\
|
||||
"version":"针对微信支付的版本号(目前可能为2,3),如果不填则按照mchId非空与否来做判断",\\
|
||||
"paySignKey":"微信支付中调用API的密钥"}
|
||||
|
||||
|
||||
@ -4,8 +4,8 @@ account={"id":"appid","secret":"appsecret",\
|
||||
"encodingAesKey":"\u516c\u4f17\u53f7\u8bbe\u7f6e\u4e86\u52a0\u5bc6\u65b9\u5f0f\u4e14\u4e3a\u300c\u5b89\u5168\u6a21\u5f0f\u300d\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"mchId":"V3.x\u7248\u672c\u4e0b\u7684\u5fae\u4fe1\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"version":\u6570\u5b57\u7c7b\u578b(2\u6216\u80053):\u5fae\u4fe1\u652f\u4ed8\u7684\u7248\u672c,\u5927\u6982\u57282014-09-14\u4e4b\u524d\u7533\u8bf7\u5e76\u4e14\u901a\u8fc7\u7684\u516c\u4f17\u53f7\u4e3aV2,\u5728\u8fd9\u4e4b\u540e\u5219\u4e3aV3 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165,\
|
||||
"partnerId":"\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"partnerKey":"\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"partnerId":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u7684\u5546\u6237\u53f7 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"partnerKey":"V2\u7248\u672c\u4e0b\u7684\u8d22\u4ed8\u901a\u5546\u6237\u6743\u9650\u5bc6\u94a5Key \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165",\
|
||||
"paySignKey":"\u5fae\u4fe1\u652f\u4ed8\u4e2d\u8c03\u7528API\u7684\u5bc6\u94a5 \u670d\u52a1\u53f7\u652f\u4ed8\u65f6\u9700\u8981\u586b\u5165"}
|
||||
|
||||
# \u4f7f\u7528FileTokenHolder\u65f6token\u7684\u5b58\u653e\u8def\u5f84
|
||||
|
||||
@ -4,12 +4,14 @@ 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.JsonResult;
|
||||
import com.foxinmy.weixin4j.http.Response;
|
||||
import com.foxinmy.weixin4j.model.Button;
|
||||
import com.foxinmy.weixin4j.model.Token;
|
||||
import com.foxinmy.weixin4j.token.TokenHolder;
|
||||
import com.foxinmy.weixin4j.type.ButtonType;
|
||||
|
||||
/**
|
||||
* 菜单相关API
|
||||
@ -48,7 +50,20 @@ public class MenuApi extends QyApi {
|
||||
obj.put("button", btnList);
|
||||
Response response = request
|
||||
.post(String.format(menu_create_uri, token.getAccessToken(),
|
||||
agentid), obj.toJSONString());
|
||||
agentid), JSON.toJSONString(obj, new NameFilter() {
|
||||
@Override
|
||||
public String process(Object object, String name,
|
||||
Object value) {
|
||||
if (object instanceof Button && name.equals("content")) {
|
||||
if (((Button) object).getFormatType() == ButtonType.view) {
|
||||
return "url";
|
||||
} else {
|
||||
return "key";
|
||||
}
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}));
|
||||
|
||||
return response.getAsJsonResult();
|
||||
}
|
||||
@ -70,8 +85,18 @@ public class MenuApi extends QyApi {
|
||||
Response response = request.get(String.format(menu_get_uri,
|
||||
token.getAccessToken(), agentid));
|
||||
|
||||
String text = response.getAsJson().getJSONObject("menu")
|
||||
.getString("button");
|
||||
String text = JSON.toJSONString(
|
||||
response.getAsJson().getJSONObject("menu")
|
||||
.getJSONArray("button"), new NameFilter() {
|
||||
@Override
|
||||
public String process(Object object, String name,
|
||||
Object value) {
|
||||
if (name.equals("url") || name.equals("key")) {
|
||||
return "content";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
});
|
||||
return JSON.parseArray(text, Button.class);
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user