package org.nutz.weixin.impl; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.nutz.http.Http; import org.nutz.http.Request; import org.nutz.http.Request.METHOD; import org.nutz.http.Response; import org.nutz.http.Sender; import org.nutz.http.sender.FilePostSender; import org.nutz.json.Json; import org.nutz.lang.ContinueLoop; import org.nutz.lang.Each; import org.nutz.lang.ExitLoop; import org.nutz.lang.Lang; import org.nutz.lang.LoopException; import org.nutz.lang.Strings; import org.nutz.lang.util.NutMap; import org.nutz.log.Log; import org.nutz.log.Logs; import org.nutz.resource.NutResource; import org.nutz.weixin.bean.WxGroup; import org.nutz.weixin.bean.WxMaster; import org.nutz.weixin.bean.WxMenu; import org.nutz.weixin.bean.WxOutMsg; import org.nutz.weixin.bean.WxTemplateData; import org.nutz.weixin.bean.WxUser; import org.nutz.weixin.spi.WxAPI; import org.nutz.weixin.util.Wxs; @SuppressWarnings("unchecked") @Deprecated public class WxApiImpl implements WxAPI { private static final Log log = Logs.get(); protected String base = "https://api.weixin.qq.com/cgi-bin"; protected WxMaster master; public WxApiImpl(WxMaster master) { super(); this.master = master; } public void send(WxOutMsg out) { if (out.getFromUserName() == null) out.setFromUserName(master.getOpenid()); String str = Wxs.asJson(out); if (Wxs.DEV_MODE) log.debug("api out msg>\n" + str); call("/message/custom/send", METHOD.POST, str); } public WxGroup createGroup(WxGroup group) { Map<String, Object> map = call("/groups/create", METHOD.POST, Json.toJson(new NutMap().setv("group", group))); return Lang.map2Object((Map<String, Object>) map.get("group"), WxGroup.class); } public List<WxGroup> listGroup() { Map<String, Object> map = call("/groups/get", METHOD.GET, null); List<Map<String, Object>> list = (List<Map<String, Object>>) map.get("groups"); List<WxGroup> groups = new ArrayList<WxGroup>(); for (Map<String, Object> e : list) { groups.add(Lang.map2Object(e, WxGroup.class)); } return groups; } public int userGroup(String openid) { Map<String, Object> map = call("/groups/getid", METHOD.POST, Json.toJson(new NutMap().setv("openid", openid))); return ((Number) map.get("groupid")).intValue(); } public void renameGroup(WxGroup group) { call("/groups/update", METHOD.POST, Json.toJson(group)); } public void moveUser2Group(String openid, String groupid) { call("/groups/members/update", METHOD.POST, Json.toJson(new NutMap().setv("openid", openid).setv("groupid", groupid))); } public WxUser fetchUser(String openid, String lang) { if (lang == null) lang = "zh_CN"; Map<String, Object> map = call("/user/info?openid=" + openid + "&lang=" + openid, METHOD.GET, null); return Lang.map2Object(map, WxUser.class); } public void listWatcher(Each<String> each) { String next_openid = null; Map<String, Object> map = null; int count = 0; int total = 0; int index = 0; while (true) { if (next_openid == null) map = call("/user/get", METHOD.GET, null); else map = call("/user/get?next_openid=" + next_openid, METHOD.GET, null); count = ((Number) map.get("count")).intValue(); if (count < 1) return; total = ((Number) map.get("total")).intValue(); next_openid = Strings.sNull(map.get("next_openid")); if (next_openid.length() == 0) next_openid = null; List<String> openids = (List<String>) ((Map<String, Object>) map.get("data")).get("openid"); for (String openid : openids) { try { each.invoke(index, openid, total); } catch (ExitLoop e) { return; } catch (ContinueLoop e) { continue; } catch (LoopException e) { throw e; } index++; } } } public void creatMenu(WxMenu menu) { call("/menu/create", METHOD.POST, Json.toJson(menu)); } public WxMenu fetchMenu() { Map<String, Object> map = call("/menu/get", METHOD.GET, null); return Lang.map2Object((Map<String, Object>) map.get("menu"), WxMenu.class); } public void clearMenu() { call("/menu/clear", METHOD.GET, null); } public String tmpQr(int expire_seconds, String scene_id) { NutMap map = new NutMap().setv("expire_seconds", expire_seconds) .setv("action_name", "QR_SCENE") .setv("scene", new NutMap().setv("scene_id", scene_id)); return call("", METHOD.POST, Json.toJson(map)).get("ticket").toString(); } public String godQr(int scene_id) { NutMap map = new NutMap().setv("action_name", "QR_LIMIT_SCENE") .setv("scene", new NutMap().setv("scene_id", scene_id)); return call("", METHOD.POST, Json.toJson(map)).get("ticket").toString(); } public String qrUrl(String ticket) { return base + "/showqrcode?ticket=" + ticket; } public void reflushAccessToken() { String url = String.format("%s/token?grant_type=client_credential&appid=%s&secret=%s", base, master.getAppid(), master.getAppsecret()); Response resp = Http.get(url); if (!resp.isOK()) throw new IllegalArgumentException("reflushAccessToken FAIL , openid=" + master.getOpenid()); String str = resp.getContent(); Map<String, Object> map = (Map<String, Object>) Json.fromJson(str); master.setAccess_token(map.get("token").toString()); master.setAccess_token_expires(System.currentTimeMillis() + (((Number) map.get("expires_in")).intValue() - 60) * 1000); } protected Map<String, Object> call(String URL, METHOD method, String body) { String token = getAccessToken(); if (URL.contains("?")) { URL = base + URL + "&access_token=" + token; } else { URL = base + URL + "?access_token=" + token; } Request req = Request.create(URL, method); if (body != null) req.setData(body); Response resp = Sender.create(req).send(); if (!resp.isOK()) throw new IllegalArgumentException("resp code=" + resp.getStatus()); Map<String, Object> map = (Map<String, Object>) Json.fromJson(resp.getReader()); if (map != null && map.containsKey("errcode") && ((Number) map.get("errcode")).intValue() != 0) { throw new IllegalArgumentException(map.toString()); } return map; } public String getAccessToken() { String token = master.getAccess_token(); if (token == null || master.getAccess_token_expires() < System.currentTimeMillis()) { synchronized (master) { if (token == null || master.getAccess_token_expires() < System.currentTimeMillis()) { reflushAccessToken(); token = master.getAccess_token(); } } } return token; } @Override public String mediaUpload(String type, File f) { if (type == null) throw new NullPointerException("media type is NULL"); if (f == null) throw new NullPointerException("meida file is NULL"); String url = String.format("http://file.api.weixin.qq.com/cgi-bin/media/upload?token=%s&type=%s", getAccessToken(), type); Request req = Request.create(url, METHOD.POST); req.getParams().put("media", f); Response resp = new FilePostSender(req).send(); if (!resp.isOK()) throw new IllegalStateException("media upload file, resp code=" + resp.getStatus()); Map<String, Object> map = (Map<String, Object>) Json.fromJson(resp.getReader()); if (map != null && map.containsKey("errcode") && ((Number) map.get("errcode")).intValue() != 0) { throw new IllegalArgumentException(map.toString()); } return map.get("media_id").toString(); } @Override public NutResource mediaGet(String mediaId) { String url = "http://file.api.weixin.qq.com/cgi-bin/media/get"; Map<String, Object> params = new HashMap<String, Object>(); params.put("token", getAccessToken()); params.put("media_id", mediaId); final Response resp = Sender.create(Request.create(url, METHOD.GET)).send(); if (!resp.isOK()) throw new IllegalStateException("download media file, resp code=" + resp.getStatus()); final String disposition = resp.getHeader().get("Content-disposition"); return new NutResource() { public String getName() { if (disposition == null) return "file.data"; for (String str : disposition.split(";")) { if (str.startsWith("filename=")) { str = str.substring("filename=".length()); if (str.startsWith("\"")) str = str.substring(1); if (str.endsWith("\"")) str = str.substring(0, str.length() - 1); return str.trim().intern(); } } return "file.data"; } public InputStream getInputStream() throws IOException { return resp.getStream(); } }; } public String sendTemplateMsg(String touser, String template_id, String topcolor, Map<String, WxTemplateData> data) { if (Strings.isBlank(topcolor)) topcolor = WxTemplateData.DFT_COLOR; NutMap map = new NutMap(); map.put("touser", touser); map.put("template_id", template_id); map.put("topcolor", topcolor); map.put("data", data); return call("/message/template/send", METHOD.POST, Json.toJson(map)).get("msgid") .toString(); } public void userRemark(String openid, String remark) { NutMap map = new NutMap(); map.put("openid", openid); map.put("remark", remark); call("/user/info/updateremark", METHOD.POST, Json.toJson(map)); } }