View Javadoc
1   package com.foxinmy.weixin4j.mp.api;
2   
3   import java.util.ArrayList;
4   import java.util.List;
5   
6   import com.alibaba.fastjson.JSON;
7   import com.alibaba.fastjson.JSONArray;
8   import com.alibaba.fastjson.JSONObject;
9   import com.alibaba.fastjson.TypeReference;
10  import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
11  import com.foxinmy.weixin4j.exception.WeixinException;
12  import com.foxinmy.weixin4j.http.weixin.ApiResult;
13  import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
14  import com.foxinmy.weixin4j.model.Button;
15  import com.foxinmy.weixin4j.model.Token;
16  import com.foxinmy.weixin4j.mp.model.AutoReplySetting;
17  import com.foxinmy.weixin4j.mp.model.MenuSetting;
18  import com.foxinmy.weixin4j.mp.model.SemQuery;
19  import com.foxinmy.weixin4j.mp.model.SemResult;
20  import com.foxinmy.weixin4j.token.TokenManager;
21  import com.foxinmy.weixin4j.tuple.MpArticle;
22  
23  /**
24   * 辅助相关API
25   *
26   * @className HelperApi
27   * @author jinyu(foxinmy@gmail.com)
28   * @date 2014年9月26日
29   * @since JDK 1.6
30   * @see
31   */
32  public class HelperApi extends MpApi {
33  
34      private final TokenManager tokenManager;
35  
36      public HelperApi(TokenManager tokenManager) {
37          this.tokenManager = tokenManager;
38      }
39  
40      /**
41       * 长链接转短链接
42       *
43       * @param url
44       *            待转换的链接
45       * @return 短链接
46       * @throws WeixinException
47       * @see <a href=
48       *      "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1443433600&token=&lang=zh_CN">长链接转短链接</a>
49       */
50      public String getShorturl(String url) throws WeixinException {
51          String shorturl_uri = getRequestUri("shorturl_uri");
52          Token token = tokenManager.getCache();
53          JSONObject obj = new JSONObject();
54          obj.put("action", "long2short");
55          obj.put("long_url", url);
56          WeixinResponse response = weixinExecutor.post(String.format(shorturl_uri, token.getAccessToken()),
57                  obj.toJSONString());
58  
59          return response.getAsJson().getString("short_url");
60      }
61  
62      /**
63       * 语义理解
64       *
65       * @param semQuery
66       *            语义理解协议
67       * @return 语义理解结果
68       * @see com.foxinmy.weixin4j.mp.model.SemQuery
69       * @see com.foxinmy.weixin4j.mp.model.SemResult
70       * @see <a href=
71       *      "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421141241&token=&lang=zh_CN">语义理解</a>
72       * @throws WeixinException
73       */
74      public SemResult semantic(SemQuery semQuery) throws WeixinException {
75          String semantic_uri = getRequestUri("semantic_uri");
76          Token token = tokenManager.getCache();
77          WeixinResponse response = weixinExecutor.post(String.format(semantic_uri, token.getAccessToken()),
78                  semQuery.toJson());
79          return response.getAsObject(new TypeReference<SemResult>() {
80          });
81      }
82  
83      /**
84       * 获取微信服务器IP地址
85       *
86       * @return IP地址
87       * @see <a href=
88       *      "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1421140187&token=&lang=zh_CN">获取IP地址</a>
89       * @throws WeixinException
90       */
91      public List<String> getWechatServerIp() throws WeixinException {
92          String getcallbackip_uri = getRequestUri("getcallbackip_uri");
93          Token token = tokenManager.getCache();
94          WeixinResponse response = weixinExecutor.get(String.format(getcallbackip_uri, token.getAccessToken()));
95          return JSON.parseArray(response.getAsJson().getString("ip_list"), String.class);
96      }
97  
98      /**
99       * 获取公众号当前使用的自定义菜单的配置,如果公众号是通过API调用设置的菜单,则返回菜单的开发配置,
100      * 而如果公众号是在公众平台官网通过网站功能发布菜单,则本接口返回运营者设置的菜单配置。
101      *
102      * @return 菜单配置信息
103      * @see {@link MenuApi#getMenu()}
104      * @see <a href=
105      *      "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1434698695&token=&lang=zh_CN">获取自定义菜单配置</a>
106      * @see com.foxinmy.weixin4j.model.Button
107      * @see com.foxinmy.weixin4j.mp.model.MenuSetting
108      * @see com.foxinmy.weixin4j.tuple.MpArticle
109      * @throws WeixinException
110      */
111     public MenuSetting getMenuSetting() throws WeixinException {
112         String menu_get_selfmenu_uri = getRequestUri("menu_get_selfmenu_uri");
113         Token token = tokenManager.getCache();
114         WeixinResponse response = weixinExecutor.get(String.format(menu_get_selfmenu_uri, token.getAccessToken()));
115         JSONObject result = response.getAsJson();
116         JSONArray buttons = result.getJSONObject("selfmenu_info").getJSONArray("button");
117         List<Button> buttonList = new ArrayList<Button>(buttons.size());
118         JSONObject buttonObj = null;
119         for (int i = 0; i < buttons.size(); i++) {
120             buttonObj = buttons.getJSONObject(i);
121             if (buttonObj.containsKey("sub_button")) {
122                 buttonObj.put("sub_button", buttonObj.getJSONObject("sub_button").getJSONArray("list"));
123                 buttonObj.put("type", "popups");
124             }
125             buttonList.add(JSON.parseObject(buttonObj.toJSONString(), Button.class, ButtonExtraProcessor.global));
126         }
127         return new MenuSetting(result.getBooleanValue("is_menu_open"), buttonList);
128     }
129 
130     private static final class ButtonExtraProcessor implements ExtraProcessor {
131         private static ButtonExtraProcessor global = new ButtonExtraProcessor();
132         private static final String KEY = "news_info";
133 
134         private ButtonExtraProcessor() {
135         }
136 
137         @Override
138         public void processExtra(Object object, String key, Object value) {
139             if (KEY.equalsIgnoreCase(key)) {
140                 JSONArray news = ((JSONObject) value).getJSONArray("list");
141                 List<MpArticle> newsList = new ArrayList<MpArticle>(news.size());
142                 JSONObject article = null;
143                 for (int i = 0; i < news.size(); i++) {
144                     article = news.getJSONObject(i);
145                     article.put("show_cover_pic", article.remove("show_cover"));
146                     article.put("thumb_url", article.remove("cover_url"));
147                     article.put("url", article.remove("content_url"));
148                     article.put("content_source_url", article.remove("source_url"));
149                     newsList.add(JSON.toJavaObject(article, MpArticle.class));
150                 }
151                 ((Button) object).setExtra(newsList);
152             } else {
153                 ((Button) object).setContent(String.valueOf(value));
154             }
155         }
156     };
157 
158     /**
159      * 获取公众号当前使用的自动回复规则,包括关注后自动回复、消息自动回复(60分钟内触发一次)、关键词自动回复。
160      *
161      * @see com.foxinmy.weixin4j.mp.model.AutoReplySetting
162      * @see <a href=
163      *      "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433751299&token=&lang=zh_CN">获取自动回复规则</a>
164      * @return 自定义回复配置信息
165      * @throws WeixinException
166      */
167     public AutoReplySetting getAutoReplySetting() throws WeixinException {
168         String autoreply_setting_get_uri = getRequestUri("autoreply_setting_get_uri");
169         Token token = tokenManager.getCache();
170         WeixinResponse response = weixinExecutor.get(String.format(autoreply_setting_get_uri, token.getAccessToken()));
171 
172         JSONObject result = response.getAsJson();
173 
174         AutoReplySetting replySetting = JSON.toJavaObject(result, AutoReplySetting.class);
175         List<AutoReplySetting.Rule> ruleList = null;
176         if (result.containsKey("keyword_autoreply_info")) {
177             JSONArray keywordList = result.getJSONObject("keyword_autoreply_info").getJSONArray("list");
178             ruleList = new ArrayList<AutoReplySetting.Rule>(keywordList.size());
179             JSONObject keywordObj = null;
180             JSONArray replyList = null;
181             JSONObject replyObj = null;
182             for (int i = 0; i < keywordList.size(); i++) {
183                 keywordObj = keywordList.getJSONObject(i);
184                 AutoReplySetting.Rule rule = JSON.toJavaObject(keywordObj, AutoReplySetting.Rule.class);
185                 replyList = keywordObj.getJSONArray("reply_list_info");
186                 List<AutoReplySetting.Entry> entryList = new ArrayList<AutoReplySetting.Entry>(replyList.size());
187                 for (int j = 0; j < replyList.size(); j++) {
188                     replyObj = replyList.getJSONObject(j);
189                     if (replyObj.getString("type").equals("news")) {
190                         entryList.add(JSON.parseObject(replyObj.toJSONString(), AutoReplySetting.Entry.class,
191                                 ButtonExtraProcessor.global));
192                     } else {
193                         entryList.add(JSON.toJavaObject(replyObj, AutoReplySetting.Entry.class));
194                     }
195                 }
196                 rule.setReplyList(entryList);
197                 ruleList.add(rule);
198             }
199         }
200         replySetting.setKeywordReplyList(ruleList);
201         return replySetting;
202     }
203 
204     /**
205      * 接口调用次数调用清零:公众号调用接口并不是无限制的。为了防止公众号的程序错误而引发微信服务器负载异常,默认情况下,
206      * 每个公众号调用接口都不能超过一定限制 ,当超过一定限制时,调用对应接口会收到{"errcode":45009,"errmsg":"api freq
207      * out of limit" }错误返回码。
208      *
209      * @param appId
210      *            公众号ID
211      * @see <a href=
212      *      "https://mp.weixin.qq.com/wiki?t=resource/res_main&id=mp1433744592&token=&lang=zh_CN">接口清零</a>
213      * @return 操作结果
214      * @throws WeixinException
215      */
216     public ApiResult clearQuota(String appId) throws WeixinException {
217         String clearquota_uri = getRequestUri("clearquota_uri");
218         String body = String.format("{\"appid\":\"%s\"}", appId);
219         WeixinResponse response = weixinExecutor.post(String.format(clearquota_uri, tokenManager.getAccessToken()),
220                 body);
221         return response.getAsResult();
222     }
223 }