调整部分实现

国庆提交,一个大部分接口都完整的版本.
This commit is contained in:
jy.hu 2014-09-30 21:11:32 +08:00
parent a891ccab41
commit 150b2ae23f
89 changed files with 4788 additions and 1769 deletions

1
.gitignore vendored
View File

@ -26,3 +26,4 @@ target/*
*.log
*.tmp
Thumbs.db
/target/

50
pom.xml
View File

@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.foxinmy.weixin</groupId>
<version>0.0.1-SNAPSHOT</version>
<artifactId>weixin4j-sdk</artifactId>
<name>weixin4j-sdk</name>
<artifactId>weixin4j</artifactId>
<name>weixin4j</name>
<build>
<plugins>
@ -32,7 +32,7 @@
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>logback.xml</exclude>
<exclude>*.*</exclude>
</excludes>
</resource>
<resource>
@ -43,7 +43,7 @@
</includes>
</resource>
</resources>
<finalName>weixin4j-sdk</finalName>
<finalName>weixin4j</finalName>
</build>
<dependencies>
<dependency>
@ -58,14 +58,9 @@
<version>${xstream.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
<version>${commons.httpclient.version}</version>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
@ -77,6 +72,16 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpmime</artifactId>
<version>${httpclient.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons.codec.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
@ -125,7 +130,23 @@
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.jsoup</groupId>
<artifactId>jsoup</artifactId>
<version>${jsoup.version}</version>
</dependency>
<dependency>
<groupId>jaxen</groupId>
<artifactId>jaxen</artifactId>
<version>${jaxen.version}</version>
</dependency>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
</dependencies>
<properties>
<junit.version>4.8.2</junit.version>
<dom4j.version>1.6.1</dom4j.version>
@ -133,9 +154,12 @@
<jcl.over.version>1.7.6</jcl.over.version>
<log4j.over.version>1.7.6</log4j.over.version>
<xstream.version>1.4.7</xstream.version>
<commons.httpclient.version>3.1</commons.httpclient.version>
<httpclient.version>4.2.5</httpclient.version>
<commons.codec.version>1.9</commons.codec.version>
<fastjson.version>1.1.9</fastjson.version>
<jsoup.version>1.7.3</jsoup.version>
<jaxen.version>1.1.6</jaxen.version>
<jedis.version>2.6.0</jedis.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<profiles>

View File

@ -0,0 +1,540 @@
package com.foxinmy.weixin4j;
import java.io.Serializable;
import java.net.URI;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.cookie.Cookie;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.jsoup.Jsoup;
import org.jsoup.helper.StringUtil;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.util.IOUtil;
/**
* 用于微信公众号绑定(模拟登录|启用开发者模式|修改服务器配置|修改回调地址|创建自定义菜单)
*
* @className WeixinBind
* @author jy
* @date 2014年8月15日
* @since JDK 1.7
* @see
*/
public class WeixinExecutor implements Serializable {
private static final long serialVersionUID = 4253859892138066462L;
private final Logger logger = LoggerFactory.getLogger(getClass());
private final static Charset charset = Charset.forName("utf-8");
private final static Map<String, String> accountMap = new HashMap<String, String>() {
private static final long serialVersionUID = 1L;
{
put("名称", "name");
put("头像", "avatar");
put("登录邮箱", "loginEmail");
put("原始ID", "originalId");
put("微信号", "weixinNo");
put("类型", "accountType");
put("认证情况", "weixinVerify");
put("介绍", "introduce");
put("所在地址", "address");
put("二维码", "qrcodeUrl");
}
};
private AbstractHttpClient client;
private HttpHost host;
private JSONObject weixin;
// 服务器响应地址
private String pushurl;
// oauth授权回调地址
private String backurl;
// 服务器校验token
private String token;
// 公众号用户名
private String uname;
// 公众号密码
private String pwd;
// 登录时验证码(如果有)
private String imgcode;
// 当要求输入验证码时,cookie需带上
private String sig;
public WeixinExecutor(String backurl, String pushurl, String token, String uname, String pwd, String imgcode, String sig) {
this.backurl = backurl;
this.pushurl = pushurl;
this.token = token;
this.uname = uname;
this.pwd = pwd;
this.imgcode = StringUtil.isBlank(imgcode) ? "" : imgcode;
this.sig = sig;
weixin = new JSONObject();
weixin.put("host", "mp.weixin.qq.com");
weixin.put("base", "https://mp.weixin.qq.com");
weixin.put("auth", "https://mp.weixin.qq.com/cgi-bin/login?lang=zh_CN");
weixin.put("call", "https://mp.weixin.qq.com/advanced/callbackprofile?t=ajax-response&token=%s&lang=zh_CN");
weixin.put("start", "https://mp.weixin.qq.com/misc/skeyform?form=advancedswitchform");
weixin.put("back", "https://mp.weixin.qq.com/merchant/myservice?action=set_oauth_domain&f=json");
weixin.put("verifycode", "https://mp.weixin.qq.com/cgi-bin/verifycode?username=" + uname + "&r=%s");
List<BasicHeader> headers = new ArrayList<BasicHeader>();
headers.add(new BasicHeader("Origin", weixin.getString("base")));
headers.add(new BasicHeader("Connection", "keep-alive"));
headers.add(new BasicHeader("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_9_4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/36.0.1985.143 Safari/537.36"));
client = new DefaultHttpClient();
client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.BROWSER_COMPATIBILITY);
client.getParams().setBooleanParameter("http.protocol.single-cookie-header", true);
client.getParams().setParameter(ClientPNames.DEFAULT_HEADERS, headers);
host = new HttpHost(weixin.getString("host"), -1, "https");
}
public JSONObject process() {
// 1.登陆微信公众号
step1_login();
int code = weixin.getIntValue("code");
if (code == 0) {
// 2.收集相关信息
step2_collect();
code = weixin.getIntValue("code");
// 3.填写服务器配置
// 3-1.未初始化账号
// 3-2.已配置账号
if (code == 0) {
step3_setting();
}
code = weixin.getIntValue("code");
// 4.修改网页授权地址
if (code == 0) {
step4_back();
}
// 5.创建底部菜单 (调用封装好的API)
// 5-1.订阅号
// 5-2.服务号
// 6.完成
}
return weixin;
}
/**
* step1:登录操作
*/
private void step1_login() {
HttpPost method = new HttpPost(weixin.getString("auth"));
try {
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("username", uname));
parameters.add(new BasicNameValuePair("pwd", DigestUtils.md5Hex(pwd.getBytes())));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("imgcode", imgcode));
if (!StringUtil.isBlank(imgcode)) {
method.addHeader("Cookie", "sig=" + sig);
}
method.setEntity(new UrlEncodedFormEntity(parameters, charset));
method.addHeader("Referer", weixin.getString("base"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step1_login--->status={},body=\n{}", line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
String msg = "";
int code = 0;
switch (body.getJSONObject("base_resp").getIntValue("ret")) {
case -1:
msg = "系统错误,请稍候再试。";
code = -1;
break;
case -2:
msg = "帐号或密码错误。";
code = 100;
break;
case -23:
msg = "您输入的帐号或者密码不正确,请重新输入。";
code = 101;
break;
case -21:
msg = "不存在该帐户。";
code = 102;
break;
case -7:
msg = "您目前处于访问受限状态。";
code = 103;
break;
case -8:
msg = "请输入图中的验证码";
code = 104;
break;
case -27:
msg = "您输入的验证码不正确,请重新输入";
code = 105;
break;
case -26:
msg = "该公众会议号已经过期,无法再登录使用。";
code = 106;
break;
case 0:
msg = "成功登录,正在跳转...";
break;
case -25:
msg = "海外帐号请在公众平台海外版登录,<a href=\"http://admin.wechat.com/\">点击登录</a>";
code = 107;
break;
default:
msg = "未知错误";
code = 108;
break;
}
if (code == 0) {
weixin.put("urlToken", getQueryMap(body.getString("redirect_url")).get("token"));
weixin.put("indexUrl", String.format("%s%s", weixin.getString("base"), body.getString("redirect_url")));
weixin.put("step", "1");
} else {
if (code == 104 || code == 105) {
// 下载验证码
HttpGet get = new HttpGet(String.format(weixin.getString("verifycode"), System.currentTimeMillis()));
get.setHeaders(method.getAllHeaders());
response = client.execute(host, get);
StringBuffer base64 = new StringBuffer();
base64.append("data:").append(response.getFirstHeader("Content-Type").getValue()).append(";base64,");
base64.append(new String(Base64.encodeBase64(IOUtil.toByteArray(response.getEntity().getContent())), charset));
weixin.put("verifydata", base64.toString());
List<Cookie> cookieList = client.getCookieStore().getCookies();
for (Cookie cookie : cookieList) {
if (cookie.getName().equals("sig")) {
weixin.put("sig", cookie.getValue());
break;
}
}
}
weixin.put("code", code);
weixin.put("msg", msg);
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step1_login catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step2:收集信息
*/
private void step2_collect() {
String url = weixin.getString("indexUrl");
HttpGet method = new HttpGet(url);
try {
method.addHeader("Referer", weixin.getString("base"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step2_setting--->status={},body=\n{}", line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
Element ele = root.getElementById("menuBar").getElementsByTag("dl").last();
url = ele.getElementsByTag("a").last().absUrl("href");
weixin.put("developerUrl", url);
method.addHeader("Referer", url);
url = ele.previousElementSibling().getElementsByTag("a").first().absUrl("href");
weixin.put("settingUrl", url);
method.setURI(URI.create(url));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base"));
line = response.getStatusLine();
weixin.put("step", "2-1");
// 公众号配置页面
if (line.getStatusCode() == HttpStatus.SC_OK) {
Elements eles = root.getElementById("settingArea").getElementsByTag("li");
String key, value;
for (Element element : eles) {
key = element.getElementsByTag("h4").first().text();
ele = element.getElementsByClass("meta_content").first();
if (ele.children().isEmpty()) {
value = ele.text();
} else {
if (ele.child(0).tagName().equalsIgnoreCase("a")) {
value = ele.child(0).absUrl("href");
} else if (ele.child(0).tagName().equalsIgnoreCase("img")) {
value = ele.child(0).absUrl("src");
} else {
value = ele.text();
}
}
weixin.put(accountMap.get(key), value);
}
weixin.put("isVerify", weixin.getString("weixinVerify").contains("微信认证"));
weixin.put("isService", weixin.getString("accountType").contains("服务号"));
weixin.put("isSubscribe", weixin.getString("accountType").contains("订阅号"));
value = weixin.getString("qrcodeUrl");
method.setURI(URI.create(value));
response = client.execute(host, method);
weixin.put("qrcodeData", IOUtil.toByteArray(response.getEntity().getContent()));
weixin.put("step", "2-2");
// 开发者页面
method.addHeader("Referer", url);
method.setURI(URI.create(weixin.getString("developerUrl")));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base"));
line = response.getStatusLine();
if (line.getStatusCode() == HttpStatus.SC_OK) {
// 初始化状态
// 配置未启用状态
// 配置已启用状态
eles = root.getElementsByClass("developer_info_opr");
if (eles != null && eles.hasText()) {
weixin.put("developerModifyUrl", eles.first().children().last().absUrl("href"));
weixin.put("status", eles.first().children().first().text().contains("启用") ? "READY" : "RUNNING");
} else {
weixin.put("status", "INIT");
}
// appid&appsecret
if (weixin.getBooleanValue("isService") || (weixin.getBooleanValue("isSubscribe") && weixin.getBooleanValue("isVerify"))) {
eles = root.getElementsByClass("developer_info_item").first().children().last().getElementsByClass("frm_controls");
weixin.put("appId", eles.first().text());
weixin.put("appSecret", eles.last().text().replace("重置", "").trim());
}
weixin.put("step", "2-3");
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step2_collect catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step3:填写配置
*/
private void step3_setting() {
HttpPost method = new HttpPost(String.format(weixin.getString("call"), weixin.getString("urlToken")));
try {
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("url", pushurl));
parameters.add(new BasicNameValuePair("callback_token", token));
method.setEntity(new UrlEncodedFormEntity(parameters, charset));
method.addHeader("Referer", weixin.getString("developerModifyUrl"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step3_setting--->status={},body=\n{}", line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
String msg = "";
int code = 0;
switch (body.getIntValue("ret")) {
case -201:
msg = "无效的URL";
code = 200;
break;
case -202:
msg = "无效的Token";
code = 201;
break;
case -203:
msg = "操作频率太快,请休息一下。";
code = 202;
break;
case -204:
msg = "请先在设置页面完善当前帐号信息";
code = 203;
break;
case -205:
msg = "该URL可能存在安全风险请检查";
code = 207;
case -301:
msg = "请求URL超时";
code = 204;
break;
case -302:
msg = "服务器没有正确响应Token验证请稍后重试";
code = 205;
break;
case -104:
msg = "参数错误,请重新填写。";
code = 206;
break;
case 0:
msg = "配置成功..";
break;
default:
msg = "未知错误";
code = 108;
break;
}
if (code == 0) {
// 触发启用按钮
if (!weixin.getString("status").equals("RUNNING")) {
parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("token", weixin.getString("urlToken")));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("ajax", "1"));
parameters.add(new BasicNameValuePair("flag", "1"));
parameters.add(new BasicNameValuePair("type", "2"));
parameters.add(new BasicNameValuePair("lang", "zh_CN"));
parameters.add(new BasicNameValuePair("random", System.currentTimeMillis() + ""));
method.setEntity(new UrlEncodedFormEntity(parameters, charset));
method.setURI(URI.create(weixin.getString("start")));
response = client.execute(host, method);
entity = response.getEntity();
root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base"));
line = response.getStatusLine();
logger.info("step3_setting--->status={},body=\n{}", line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
body = JSON.parseObject(root.body().text());
if (body.getIntValue("ret") != 0 || body.getJSONObject("base_resp").getIntValue("ret") != 0) {
weixin.put("code", 300);
weixin.put("msg", "启用开发者模式失败,请稍后再试!");
}
}
}
weixin.put("step", "3");
} else {
weixin.put("code", code);
weixin.put("msg", msg);
}
} else {
weixin.put("code", "-3");
weixin.put("msg", "网络异常,请稍后重试!");
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step3_setting catch error", e);
} finally {
if (weixin.getIntValue("code") != 0) {
client.getConnectionManager().shutdown();
}
}
}
/**
* step4:修改回调
*/
private void step4_back() {
try {
if (weixin.getBooleanValue("isVerify")) {
HttpPost method = new HttpPost(weixin.getString("back"));
List<NameValuePair> parameters = new ArrayList<NameValuePair>();
parameters.add(new BasicNameValuePair("domain", backurl));
parameters.add(new BasicNameValuePair("token", weixin.getString("urlToken")));
parameters.add(new BasicNameValuePair("f", "json"));
parameters.add(new BasicNameValuePair("ajax", "1"));
parameters.add(new BasicNameValuePair("flag", "1"));
parameters.add(new BasicNameValuePair("lang", "zh_CN"));
parameters.add(new BasicNameValuePair("random", System.currentTimeMillis() + ""));
method.setEntity(new UrlEncodedFormEntity(parameters, charset));
method.addHeader("Referer", weixin.getString("developerUrl"));
HttpResponse response = client.execute(host, method);
HttpEntity entity = response.getEntity();
Document root = Jsoup.parse(entity.getContent(), charset.name(), weixin.getString("base"));
StatusLine line = response.getStatusLine();
logger.info("step4_back--->status={},body=\n{}", line, root.toString());
if (line.getStatusCode() == HttpStatus.SC_OK) {
JSONObject body = JSON.parseObject(root.body().text());
if (body.getIntValue("ret") != 0 || body.getJSONObject("base_resp").getIntValue("ret") != 0) {
weixin.put("code", "400");
weixin.put("msg", "修改授权回调地址失败!");
}
weixin.put("step", "4");
}
} else {
logger.info("公众号尚未认证,放弃本次修改授权回调地址操作。{}", weixin);
}
} catch (Exception e) {
weixin.put("code", "-2");
weixin.put("msg", "服务器繁忙,请稍后重试!");
weixin.put("exception", e.getMessage());
logger.error("step4_back catch error", e);
} finally {
client.getConnectionManager().shutdown();
}
}
private Map<String, String> getQueryMap(String query) {
String[] params = query.split("&");
Map<String, String> map = new HashMap<String, String>();
for (String param : params) {
String name = param.split("=")[0];
String value = param.split("=")[1];
map.put(name, value);
}
return map;
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,15 @@
package com.foxinmy.weixin4j.api;
import com.foxinmy.weixin4j.http.HttpRequest;
/**
*
* @className BaseApi
* @author jy.hu
* @date 2014年9月26日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php">api文档</a>
*/
public class BaseApi {
protected final HttpRequest request = new HttpRequest();
}

View File

@ -0,0 +1,142 @@
package com.foxinmy.weixin4j.api;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Group;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.msg.BaseResult;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 分组相关API
*
* @className GroupApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%
* BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3">分组接口</a>
* @see com.foxinmy.weixin4j.model.Group
*/
public class GroupApi extends BaseApi {
private final TokenApi tokenApi;
public GroupApi(TokenApi tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 创建分组
*
* @param name
* 组名称
* @return group对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E5.88.9B.E5.BB.BA.E5.88.86.E7.BB.84">创建分组</a>
* @see com.foxinmy.weixin4j.model.Group
* @see com.foxinmy.weixin4j.model.Group#toCreateJson()
*/
public Group createGroup(String name) throws WeixinException {
String group_create_uri = ConfigUtil.getValue("group_create_uri");
Token token = tokenApi.getToken();
Group group = new Group(name);
Response response = request.post(
String.format(group_create_uri, token.getAccessToken()),
group.toCreateJson());
return response.getAsJson().getObject("group", Group.class);
}
/**
* 查询所有分组
*
* @return 组集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E6.9F.A5.E8.AF.A2.E6.89.80.E6.9C.89.E5.88.86.E7.BB.84">查询所有分组</a>
* @see com.foxinmy.weixin4j.model.Group
*/
public List<Group> getGroups() throws WeixinException {
String group_get_uri = ConfigUtil.getValue("group_get_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(group_get_uri,
token.getAccessToken()));
return JSON.parseArray(response.getAsJson().getString("groups"),
Group.class);
}
/**
* 查询用户所在分组
*
* @param openId
* 用户对应的ID
* @return 组ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E6.9F.A5.E8.AF.A2.E7.94.A8.E6.88.B7.E6.89.80.E5.9C.A8.E5.88.86.E7.BB.84">查询用户所在分组</a>
* @see com.foxinmy.weixin4j.model.Group
*/
public int getGroupByOpenId(String openId) throws WeixinException {
String group_getid_uri = ConfigUtil.getValue("group_getid_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(group_getid_uri, token.getAccessToken()),
String.format("{\"openid\":\"%s\"}", openId));
return response.getAsJson().getIntValue("groupid");
}
/**
* 修改分组名
*
* @param groupId
* 组ID
* @param name
* 组名称
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E4.BF.AE.E6.94.B9.E5.88.86.E7.BB.84.E5.90.8D">修改分组名</a>
* @see com.foxinmy.weixin4j.model.Group
* @see com.foxinmy.weixin4j.model.Group#toModifyJson()
*/
public BaseResult modifyGroup(int groupId, String name)
throws WeixinException {
String group_modify_uri = ConfigUtil.getValue("group_modify_uri");
Token token = tokenApi.getToken();
Group group = new Group(groupId, name);
Response response = request.post(
String.format(group_modify_uri, token.getAccessToken()),
group.toModifyJson());
return response.getAsResult();
}
/**
* 移动分组
*
* @param openId
* 用户对应的ID
* @param groupId
* 组ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%88%86%E7%BB%84%E7%AE%A1%E7%90%86%E6%8E%A5%E5%8F%A3#.E7.A7.BB.E5.8A.A8.E7.94.A8.E6.88.B7.E5.88.86.E7.BB.84">移动分组</a>
* @see com.foxinmy.weixin4j.model.Group
*/
public BaseResult moveGroup(String openId, int groupId)
throws WeixinException {
String group_move_uri = ConfigUtil.getValue("group_move_uri");
Token token = tokenApi.getToken();
Response response = request.post(String.format(group_move_uri,
token.getAccessToken()), String.format(
"{\"openid\":\"%s\",\"to_groupid\":%d}", openId, groupId));
return response.getAsResult();
}
}

View File

@ -0,0 +1,45 @@
package com.foxinmy.weixin4j.api;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 辅助相关API
*
* @className HelperApi
* @author jy.hu
* @date 2014年9月26日
* @since JDK 1.7
* @see
*/
public class HelperApi extends BaseApi {
private final TokenApi tokenApi;
public HelperApi(TokenApi tokenApi){
this.tokenApi = tokenApi;
}
/**
* 长链接转短链接
*
* @param url
* @return 短链接
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%95%BF%E9%93%BE%E6%8E%A5%E8%BD%AC%E7%9F%AD%E9%93%BE%E6%8E%A5%E6%8E%A5%E5%8F%A3">长链接转短链接</a>
*/
public String getShorturl(String url) throws WeixinException {
String shorturl_uri = ConfigUtil.getValue("shorturl_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("action", "long2short");
obj.put("long_url", url);
Response response = request.post(String.format(shorturl_uri, token.getAccessToken()), obj.toJSONString());
return response.getAsJson().getString("short_url");
}
}

View File

@ -0,0 +1,270 @@
package com.foxinmy.weixin4j.api;
import java.io.File;
import java.util.List;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.MpArticle;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.msg.BaseResult;
import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 群发相关API
*
* @className MassApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3">群发接口</a>
* @see com.foxinmy.weixin4j.model.MpArticle
*/
public class MassApi extends BaseApi {
private final TokenApi tokenApi;
public MassApi(TokenApi tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 上传图文消息,一个图文消息支持1到10条图文
*
* @param articles
* 图片消息
* @return 媒体ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3">高级群发</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E4.B8.8A.E4.BC.A0.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF.E7.B4.A0.E6.9D.90">上传图文消息</a>
* @see com.foxinmy.weixin4j.model.MpArticle
*/
public String uploadArticle(List<MpArticle> articles)
throws WeixinException {
String article_upload_uri = ConfigUtil.getValue("article_upload_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("articles", articles);
Response response = request.post(
String.format(article_upload_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJson().getString("media_id");
}
/**
* 上传分组群发的视频素材
*
* @param mediaId
* 媒体文件中上传得到的Id
* @param title
* 标题 可为空
* @param desc
* 描述 可为空
* @return 上传后的ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3">高级群发</a>
* @see {@link com.foxinmy.weixin4j.api.MediaApi#uploadMedia(File, MediaType)}
*/
public String uploadVideo(String mediaId, String title, String desc)
throws WeixinException {
String video_upload_uri = ConfigUtil.getValue("video_upload_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("media_id", mediaId);
obj.put("title", title);
obj.put("description", desc);
Response response = request.post(
String.format(video_upload_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsJson().getString("media_id");
}
/**
* 分组群发
* <p>
* 在返回成功时,意味着群发任务提交成功,并不意味着此时群发已经结束,所以,仍有可能在后续的发送过程中出现异常情况导致用户未收到消息,
* 如消息有时会进行审核服务器不稳定等,此外,群发任务一般需要较长的时间才能全部发送完毕
* </p>
*
* @param jsonPara
* json格式的参数
* @param groupId
* 分组ID
* @return 发送出去的消息ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E6.A0.B9.E6.8D.AE.E5.88.86.E7.BB.84.E8.BF.9B.E8.A1.8C.E7.BE.A4.E5.8F.91">分组群发</a>
* @see com.foxinmy.weixin4j.model.Group
* @see {@link com.foxinmy.weixin4j.api.GroupApi#getGroupByOpenId(String)}
* @see {@link com.foxinmy.weixin4j.api.GroupApi#getGroups()}
*/
private String massByGroup(JSONObject jsonPara, String groupId)
throws WeixinException {
String mass_group_uri = ConfigUtil.getValue("mass_group_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(mass_group_uri, token.getAccessToken()),
jsonPara.toJSONString());
return response.getAsJson().getString("msg_id");
}
/**
* openId群发
*
* @param jsonPara
* json格式的参数
* @param openIds
* 目标ID列表
* @return 发送出去的消息ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E6.A0.B9.E6.8D.AEOpenID.E5.88.97.E8.A1.A8.E7.BE.A4.E5.8F.91">openId群发</a>
* @see com.foxinmy.weixin4j.model.User
*/
private String massByOpenIds(JSONObject jsonPara, String... openIds)
throws WeixinException {
String mass_openid_uri = ConfigUtil.getValue("mass_openid_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(mass_openid_uri, token.getAccessToken()),
jsonPara.toJSONString());
return response.getAsJson().getString("msg_id");
}
/**
* 分组群发
*
* @param mediaId
* 媒体ID 如果为text 则表示content
* @param mediaType
* 媒体类型
* @param groupId
* 分组ID
* @return
* @throws WeixinException
* @see com.foxinmy.weixin4j.model.Group
* @see com.foxinmy.weixin4j.type.MediaType
* @see {@link com.foxinmy.weixin4j.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.api.GroupApi#getGroupByOpenId(String)}
* @see {@link com.foxinmy.weixin4j.api.GroupApi#getGroups()}
* @see {@link com.foxinmy.weixin4j.api.MassApi#massByGroup(JSONObject,String)}
*/
public String massByGroup(String mediaId, MediaType mediaType,
String groupId) throws WeixinException {
JSONObject jsonPara = new JSONObject();
jsonPara.put("filter", new JSONObject().put("group_id", groupId));
jsonPara.put(mediaType.name(), new JSONObject().put(
mediaType == MediaType.text ? "content" : "media_id", mediaId));
jsonPara.put("msgtype", mediaType.name());
return massByGroup(jsonPara, groupId);
}
/**
* 分组群发图文消息
*
* @param articles
* 图文消息列表
* @param groupId
* 分组ID
* @return 发送出去的消息ID
* @throws WeixinException
* @see com.foxinmy.weixin4j.model.MpArticle
* @see com.foxinmy.weixin4j.model.Group
* @see {@link com.foxinmy.weixin4j.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.api.MassApi#uploadNews(List)}
* @see {@link com.foxinmy.weixin4j.api.MassApi#massByGroup(String,MediaType,String)}
*/
public String massArticleByGroup(List<MpArticle> articles, String groupId)
throws WeixinException {
String mediaId = uploadArticle(articles);
return massByGroup(mediaId, MediaType.mpnews, groupId);
}
/**
* openId群发
*
* @param mediaId
* 媒体ID 如果为text 则表示content
* @param mediaType
* 媒体类型
* @param openIds
* openId列表
* @return
* @throws WeixinException
* @see com.foxinmy.weixin4j.model.User
* @see com.foxinmy.weixin4j.type.MediaType
* @see {@link com.foxinmy.weixin4j.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.api.MassApi#massByOpenIds(JSONObject,String...)}
*/
public String massByOpenIds(String mediaId, MediaType mediaType,
String... openIds) throws WeixinException {
JSONObject jsonPara = new JSONObject();
jsonPara.put("touser", openIds);
jsonPara.put(mediaType.name(), new JSONObject().put(
mediaType == MediaType.text ? "content" : "media_id", mediaId));
jsonPara.put("msgtype", mediaType.name());
return massByOpenIds(jsonPara, openIds);
}
/**
* openId图文群发
*
* @param articles
* 图文消息列表
* @param openIds
* 目标ID列表
* @return 发送出去的消息ID
* @throws WeixinException
* @see com.foxinmy.weixin4j.model.MpArticle
* @see com.foxinmy.weixin4j.model.User
* @see {@link com.foxinmy.weixin4j.api.MediaApi#uploadMedia(File, MediaType)}
* @see {@link com.foxinmy.weixin4j.api.MediaApi#uploadNews(List)}
* @see {@link com.foxinmy.weixin4j.api.MassApi#massByOpenIds(String,MediaType,String...)}
*/
public String massArticleByOpenIds(List<MpArticle> articles,
String... openIds) throws WeixinException {
String mediaId = uploadArticle(articles);
return massByOpenIds(mediaId, MediaType.mpnews, openIds);
}
/**
* 删除群发消息
* <p>
* 请注意,只有已经发送成功的消息才能删除删除消息只是将消息的图文详情页失效,已经收到的用户,还是能在其本地看到消息卡片
* </p>
*
* @param msgid
* 发送出去的消息ID
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AB%98%E7%BA%A7%E7%BE%A4%E5%8F%91%E6%8E%A5%E5%8F%A3#.E5.88.A0.E9.99.A4.E7.BE.A4.E5.8F.91">删除群发</a>
* @see {@link com.foxinmy.weixin4j.api.MassApi#massByGroup(JSONObject, String)}
* @see {@link com.foxinmy.weixin4j.api.MassApi#massByOpenIds(JSONObject, String...)
*/
public BaseResult deleteMassNews(String msgid) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("msgid", msgid);
String mass_delete_uri = ConfigUtil.getValue("mass_delete_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(mass_delete_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
}

View File

@ -0,0 +1,174 @@
package com.foxinmy.weixin4j.api;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import org.apache.http.entity.mime.content.ByteArrayBody;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.PartParameter;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.IOUtil;
/**
* 媒体相关API
*
* @className MediaApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传多媒体文件</a>
* @see com.foxinmy.weixin4j.type.MediaType
*/
public class MediaApi extends BaseApi {
private final TokenApi tokenApi;
public MediaApi(TokenApi tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 上传媒体文件
* <p>
* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789},
* 否则抛出异常.
* </p>
*
* @param file
* 文件对象
* @param mediaType
* 媒体类型
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传下载说明</a>
* @see com.foxinmy.weixin4j.type.MediaType
*/
public String uploadMedia(File file, MediaType mediaType)
throws WeixinException {
byte[] b = null;
ByteArrayOutputStream out = null;
FileInputStream in = null;
try {
in = new FileInputStream(file);
b = IOUtil.toByteArray(in);
} catch (IOException e) {
e.printStackTrace();
} finally {
if (out != null) {
try {
out.close();
} catch (IOException e) {
;
}
}
if (in != null) {
try {
in.close();
} catch (IOException e) {
;
}
}
}
return uploadMedia(file.getName(), b, mediaType);
}
/**
* 上传媒体文件
*
* @param bytes
* 媒体数据包
* @param mediaType
* 媒体类型
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @see {@link com.foxinmy.weixin4j.api.MediaApi#uploadMedia(File, MediaType)}
*/
public String uploadMedia(String fileName, byte[] bytes, MediaType mediaType)
throws WeixinException {
Token token = tokenApi.getToken();
String file_upload_uri = ConfigUtil.getValue("file_upload_uri");
Response response = request.post(String.format(file_upload_uri,
token.getAccessToken(), mediaType.name()), new PartParameter(
"media", new ByteArrayBody(bytes, fileName)));
return response.getAsJson().getString("media_id");
}
/**
* 下载媒体文件
* <p>
* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常.
* </p>
*
* @param mediaId
* 存储在微信服务器上的媒体标识
* @param mediaType
* 媒体类型
* @return 写入硬盘后的文件对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%8B%E8%BD%BD%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传下载说明</a>
* @see com.foxinmy.weixin4j.type.MediaType
*/
public File downloadMedia(String mediaId, MediaType mediaType)
throws WeixinException {
String media_path = ConfigUtil.getValue("media_path");
String filename = mediaId + mediaType.getFormatType();
File file = new File(media_path + File.separator + filename);
if (file.exists()) {
return file;
}
FileOutputStream out = null;
try {
try {
file.createNewFile();
} catch (IOException e) {
file.getParentFile().mkdirs();
file.createNewFile();
}
out = new FileOutputStream(file);
byte[] b = downloadMediaData(mediaId, mediaType);
out.write(b);
} catch (IOException e) {
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
}
}
return file;
}
/**
* 下载媒体文件
*
* @param mediaId
* @param mediaType
* @return 二进制数据包
* @throws WeixinException
* @see {@link com.foxinmy.weixin4j.WeixinProxy#downloadMedia(String, MediaType)}
*/
public byte[] downloadMediaData(String mediaId, MediaType mediaType)
throws WeixinException {
Token token = tokenApi.getToken();
String file_download_uri = ConfigUtil.getValue("file_download_uri");
Response response = request.get(String.format(file_download_uri,
token.getAccessToken(), mediaId));
return response.getBody();
}
}

View File

@ -0,0 +1,89 @@
package com.foxinmy.weixin4j.api;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.api.token.TokenApi;
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.msg.BaseResult;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 菜单相关API
*
* @className MenuApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.model.Button
*/
public class MenuApi extends BaseApi {
private final TokenApi tokenApi;
public MenuApi(TokenApi tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 自定义菜单
*
* @param btnList
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3">创建自定义菜单</a>
* @see com.foxinmy.weixin4j.model.Button
*/
public BaseResult createMenu(List<Button> btnList) throws WeixinException {
String menu_create_uri = ConfigUtil.getValue("menu_create_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("button", btnList);
Response response = request.post(
String.format(menu_create_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
/**
* 查询菜单
*
* @return 菜单集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E6%9F%A5%E8%AF%A2%E6%8E%A5%E5%8F%A3">查询菜单</a>
* @see com.foxinmy.weixin4j.model.Button
*/
public List<Button> getMenu() throws WeixinException {
String menu_get_uri = ConfigUtil.getValue("menu_get_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(menu_get_uri,
token.getAccessToken()));
String text = response.getAsJson().getJSONObject("menu")
.getString("button");
return JSON.parseArray(text, Button.class);
}
/**
* 删除菜单
*
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%A0%E9%99%A4%E6%8E%A5%E5%8F%A3">删除菜单</a>
* @see com.foxinmy.weixin4j.model.Button
*/
public BaseResult deleteMenu() throws WeixinException {
String menu_delete_uri = ConfigUtil.getValue("menu_delete_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(menu_delete_uri,
token.getAccessToken()));
return response.getAsResult();
}
}

View File

@ -0,0 +1,166 @@
package com.foxinmy.weixin4j.api;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.CustomRecord;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.msg.BaseResult;
import com.foxinmy.weixin4j.msg.model.Article;
import com.foxinmy.weixin4j.msg.model.BaseMsg;
import com.foxinmy.weixin4j.msg.notify.ArticleNotify;
import com.foxinmy.weixin4j.msg.notify.BaseNotify;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 客服相关API
*
* @className NotifyApi
* @author jy.hu
* @date 2014年9月26日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF">客服消息</a>
* @see com.foxinmy.weixin4j.msg.notify.TextNotify
* @see com.foxinmy.weixin4j.msg.notify.ImageNotify
* @see com.foxinmy.weixin4j.msg.notify.MusicNotify
* @see com.foxinmy.weixin4j.msg.notify.VideoNotify
* @see com.foxinmy.weixin4j.msg.notify.VoiceNotify
* @see com.foxinmy.weixin4j.msg.notify.ArticleNotify
*/
public class NotifyApi extends BaseApi {
private final TokenApi tokenApi;
public NotifyApi(TokenApi tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 发送客服消息
*
* @param jsonPara
* @return
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">发送客服消息</a>
*/
private BaseResult sendNotify(String jsonPara) throws WeixinException {
String custom_notify_uri = ConfigUtil.getValue("custom_notify_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(custom_notify_uri, token.getAccessToken()),
jsonPara);
return response.getAsResult();
}
/**
* 发送客服消息(在48小时内不限制发送次数)
*
* @param notify
* 客服消息对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF">发送客服消息</a>
* @see com.foxinmy.weixin4j.msg.notify.TextNotify
* @see com.foxinmy.weixin4j.msg.notify.ImageNotify
* @see com.foxinmy.weixin4j.msg.notify.MusicNotify
* @see com.foxinmy.weixin4j.msg.notify.VideoNotify
* @see com.foxinmy.weixin4j.msg.notify.VoiceNotify
* @see com.foxinmy.weixin4j.msg.notify.ArticleNotify
* @see {@link com.foxinmy.weixin4j.api.NotifyApi#sendNotify(String)}
*/
public BaseResult sendNotify(BaseNotify notify) throws WeixinException {
return sendNotify(notify.toJson());
}
/**
* 发送图文消息
*
* @param touser
* 目标ID
* @param articles
* 图文列表
* @return 发送结果
* @throws WeixinException
* @see com.foxinmy.weixin4j.msg.model.Article
* @see com.foxinmy.weixin4j.msg.notify.ArticleNotify
*/
public BaseResult sendNotify(String touser, List<Article> articles)
throws WeixinException {
ArticleNotify notify = new ArticleNotify(touser);
notify.pushAll(articles);
return sendNotify(notify);
}
/**
* 发送客服消息(不包含图文消息)
*
* @param touser
* 目标用户
* @param baseMsg
* 消息类型
* @return 发送结果
* @throws WeixinException
* @see com.foxinmy.weixin4j.msg.model.Text
* @see com.foxinmy.weixin4j.msg.model.Image
* @see com.foxinmy.weixin4j.msg.model.Music
* @see com.foxinmy.weixin4j.msg.model.Video
* @see com.foxinmy.weixin4j.msg.model.Voice
* @see {@link com.foxinmy.weixin4j.msg.model.BaseMsg#toNotifyJson()}
* @see {@link com.foxinmy.weixin4j.api.NotifyApi#sendNotify(String)}
*/
public BaseResult sendNotify(String touser, BaseMsg baseMsg)
throws WeixinException {
StringBuilder jsonPara = new StringBuilder();
String mediaType = baseMsg.getMediaType().name();
jsonPara.append("{");
jsonPara.append("\"touser\":\"").append(touser).append("\",");
jsonPara.append("\"msgtype\":\"").append(mediaType).append("\",");
jsonPara.append("\"").append(mediaType).append("\":");
jsonPara.append(baseMsg.toNotifyJson()).append("}");
return sendNotify(jsonPara.toString());
}
/**
* 客服聊天记录
*
* @param openId
* 用户标识 可为空
* @param starttime
* 查询开始时间
* @param endtime
* 查询结束时间 每次查询不能跨日查询
* @param pagesize
* 每页大小 每页最多拉取1000条
* @param pageindex
* 查询第几页 从1开始
* @throws WeixinException
* @see com.foxinmy.weixin4j.model.CustomRecord
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AE%A2%E6%9C%8D%E8%81%8A%E5%A4%A9%E8%AE%B0%E5%BD%95">查询客服聊天记录</a>
*/
public List<CustomRecord> getCustomRecord(String openId, long starttime,
long endtime, int pagesize, int pageindex) throws WeixinException {
JSONObject obj = new JSONObject();
obj.put("openId", openId == null ? "" : openId);
obj.put("starttime", starttime);
obj.put("endtime", endtime);
obj.put("pagesize", pagesize > 1000 ? 1000 : pagesize);
obj.put("pageindex", pageindex);
String custom_record_uri = ConfigUtil.getValue("custom_record_uri");
Token token = tokenApi.getToken();
Response response = request.post(
String.format(custom_record_uri, token.getAccessToken()),
obj.toJSONString());
String text = response.getAsJson().getString("recordlist");
return JSON.parseArray(text, CustomRecord.class);
}
}

View File

@ -0,0 +1,115 @@
package com.foxinmy.weixin4j.api;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.QRParameter;
import com.foxinmy.weixin4j.model.QRParameter.QRType;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 二维码相关API
*
* @className QrApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81">二维码支持</a>
*/
public class QrApi extends BaseApi {
private final TokenApi tokenApi;
public QrApi(TokenApi tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 生成带参数的二维码
*
* @param parameter
* @return byte数据包
* @throws WeixinException
* @see {@link com.foxinmy.weixin4j.api.QrApi#getQR(QRParameter)}
*/
public byte[] getQRData(QRParameter parameter) throws WeixinException {
Token token = tokenApi.getToken();
String qr_uri = ConfigUtil.getValue("qr_ticket_uri");
Response response = request.post(String.format(qr_uri, token.getAccessToken()), parameter.toJson());
String ticket = response.getAsJson().getString("ticket");
qr_uri = ConfigUtil.getValue("qr_image_uri");
response = request.get(String.format(qr_uri, ticket));
return response.getBody();
}
/**
* 生成带参数的二维码
*
* @param sceneId
* 场景值
* @param expireSeconds
* 过期秒数 如果小于等于0则 视为永久二维码
* @return byte数据包
* @throws WeixinException
* @see {@link com.foxinmy.weixin4j.api.QrApi#getQR(QRParameter)}
*/
public byte[] getQRData(int sceneId, int expireSeconds) throws WeixinException {
QRParameter parameter = new QRParameter(sceneId, QRType.TEMPORARY, expireSeconds);
if (expireSeconds <= 0) {
parameter.setQrType(QRType.PERMANENCE);
}
return getQRData(parameter);
}
/**
* 生成带参数的二维码
* <p>
* 二维码分为临时跟永久两种,扫描时触发推送带参数事件
* </p>
*
* @param parameter
* 二维码参数
* @return 硬盘存储的文件对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81">二维码</a>
* @see com.foxinmy.weixin4j.model.QRParameter
*/
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());
File file = new File(qr_path + File.separator + filename);
if (parameter.getQrType() == QRType.PERMANENCE && file.exists()) {
return file;
}
FileOutputStream out = null;
try {
try {
file.createNewFile();
} catch (IOException e) {
file.getParentFile().mkdirs();
file.createNewFile();
}
out = new FileOutputStream(file);
byte[] b = getQRData(parameter);
out.write(b);
} catch (IOException e) {
;
} finally {
try {
if (out != null) {
out.close();
}
} catch (IOException e) {
;
}
}
return file;
}
}

View File

@ -0,0 +1,49 @@
package com.foxinmy.weixin4j.api;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.msg.BaseResult;
import com.foxinmy.weixin4j.msg.out.TemplateMessage;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 模板消息相关API
*
* @className TemplApi
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see
*/
public class TemplApi extends BaseApi {
private final TokenApi tokenApi;
public TemplApi(TokenApi tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 发送模板消息
*
* @param message
* @return 发送结果
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3">模板消息</a>
* @see com.foxinmy.weixin4j.msg.out.TemplateMessage
* @seee com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage
*/
public BaseResult sendTplMessage(TemplateMessage tplMessage)
throws WeixinException {
Token token = tokenApi.getToken();
String template_send_uri = ConfigUtil.getValue("template_send_uri");
Response response = request.post(
String.format(template_send_uri, token.getAccessToken()),
tplMessage.toJson());
return response.getAsResult();
}
}

View File

@ -0,0 +1,182 @@
package com.foxinmy.weixin4j.api;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Following;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.model.User;
import com.foxinmy.weixin4j.model.UserToken;
import com.foxinmy.weixin4j.msg.BaseResult;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 用户相关API
*
* @className UserApi
* @author jy.hu
* @date 2014年9月25日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.model.User
*/
public class UserApi extends BaseApi {
private final TokenApi tokenApi;
public UserApi(TokenApi tokenApi) {
this.tokenApi = tokenApi;
}
/**
* 获取token
*
* @param code
* 用户授权后返回的code
* @return token对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E4.BA.8C.E6.AD.A5.EF.BC.9A.E9.80.9A.E8.BF.87code.E6.8D.A2.E5.8F.96.E7.BD.91.E9.A1.B5.E6.8E.88.E6.9D.83access_token">获取用户token</a>
* @see com.foxinmy.weixin4j.model.UserToken
*/
public UserToken getAccessToken(String code) throws WeixinException {
String user_token_uri = ConfigUtil.getValue("sns_user_token_uri");
Response response = request.get(String.format(user_token_uri, code));
return response.getAsObject(UserToken.class);
}
/**
* 获取用户信息
*
* @param token
* 授权票据
* @return 用户对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E5.9B.9B.E6.AD.A5.EF.BC.9A.E6.8B.89.E5.8F.96.E7.94.A8.E6.88.B7.E4.BF.A1.E6.81.AF.28.E9.9C.80scope.E4.B8.BA_snsapi_userinfo.29">拉取用户信息</a>
* @see com.foxinmy.weixin4j.model.User
* @see com.foxinmy.weixin4j.model.UserToken
* {@link com.foxinmy.weixin4j.api.UserApi#getAccessToken(String)}
*/
public User getUser(UserToken token) throws WeixinException {
String user_info_uri = ConfigUtil.getValue("sns_user_info_uri");
Response response = request.get(String.format(user_info_uri,
token.getAccessToken(), token.getOpenid()));
return response.getAsObject(User.class);
}
/**
* 获取用户信息
* <p>
* 在关注者与公众号产生消息交互后,公众号可获得关注者的OpenID加密后的微信号,每个用户对每个公众号的OpenID是唯一的,对于不同公众号,
* 同一用户的openid不同,公众号可通过本接口来根据OpenID获取用户基本信息,包括昵称头像性别所在城市语言和关注时间
* </p>
*
* @param openId
* 用户对应的ID
* @return 用户对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">获取用户信息</a>
* @see com.foxinmy.weixin4j.model.User
*/
public User getUser(String openId) throws WeixinException {
String user_info_uri = ConfigUtil.getValue("api_user_info_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(user_info_uri,
token.getAccessToken(), openId));
return response.getAsObject(User.class);
}
/**
* 获取用户一定数量(10000)的关注者列表
*
* @param nextOpenId
* 下一次拉取数据的openid
* @return 关注信息
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%85%B3%E6%B3%A8%E8%80%85%E5%88%97%E8%A1%A8">获取关注者列表</a>
* @see com.foxinmy.weixin4j.model.Following
*/
public Following getFollowing(String nextOpenId) throws WeixinException {
String fllowing_uri = ConfigUtil.getValue("following_uri");
Token token = tokenApi.getToken();
Response response = request.get(String.format(fllowing_uri,
token.getAccessToken(), nextOpenId == null ? "" : nextOpenId));
Following following = response.getAsObject(Following.class);
if (following.getCount() > 0) {
List<String> openIds = JSON.parseArray(following.getDataJson()
.getString("openid"), String.class);
List<User> userList = new ArrayList<User>();
for (String openId : openIds) {
userList.add(getUser(openId));
}
following.setUserList(userList);
}
return following;
}
/**
* 获取用户全部的关注者列表
* <p>
* 当公众号关注者数量超过10000时,可通过填写next_openid的值,从而多次拉取列表的方式来满足需求,
* 将上一次调用得到的返回中的next_openid值,作为下一次调用中的next_openid值
* </p>
*
* @return 用户对象集合
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%85%B3%E6%B3%A8%E8%80%85%E5%88%97%E8%A1%A8">获取关注者列表</a>
* @see com.foxinmy.weixin4j.model.Following
* @see com.foxinmy.weixin4j.api.UserApi#getFollowing(String)
*/
public List<User> getAllFollowing() throws WeixinException {
List<User> userList = new ArrayList<User>();
String nextOpenId = null;
Following f = null;
for (;;) {
f = getFollowing(nextOpenId);
if (f.getCount() == 0) {
break;
}
userList.addAll(f.getUserList());
nextOpenId = f.getNextOpenId();
}
return userList;
}
/**
* 设置用户备注名
*
* @param openId
* 用户ID
* @param remark
* 备注名
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%AE%BE%E7%BD%AE%E7%94%A8%E6%88%B7%E5%A4%87%E6%B3%A8%E5%90%8D%E6%8E%A5%E5%8F%A3">设置用户备注名</a>
*/
public BaseResult updateUserRemark(String openId, String remark)
throws WeixinException {
String updateremark_uri = ConfigUtil.getValue("updateremark_uri");
Token token = tokenApi.getToken();
JSONObject obj = new JSONObject();
obj.put("openid", openId);
obj.put("remark", remark);
Response response = request.post(
String.format(updateremark_uri, token.getAccessToken()),
obj.toJSONString());
return response.getAsResult();
}
}

View File

@ -0,0 +1,95 @@
package com.foxinmy.weixin4j.api.token;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Calendar;
import org.jsoup.helper.StringUtil;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.HttpRequest;
import com.foxinmy.weixin4j.http.Response;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.xml.XStream;
/**
* 基于文件保存的Token获取类
*
* @className FileTokenApi
* @author jy.hu
* @date 2014年9月27日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token说明</a>
* @see com.foxinmy.weixin4j.model.Token
*/
public class FileTokenApi implements TokenApi {
private final HttpRequest request = new HttpRequest();
private final String appid;
private final String appsecret;
public FileTokenApi() {
this(ConfigUtil.getValue("app_id"), ConfigUtil.getValue("app_secret"));
}
public FileTokenApi(String appid, String appsecret) {
this.appid = appid;
this.appsecret = appsecret;
}
/**
* 获取token
* <p>
* 正常情况下返回{"access_token":"ACCESS_TOKEN","expires_in":7200},否则抛出异常.
* </p>
*
* @return token对象
* @throws WeixinException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token说明</a>
* @see com.foxinmy.weixin4j.model.Token
*/
@Override
public Token getToken() throws WeixinException {
if (StringUtil.isBlank(appid) || StringUtil.isBlank(appsecret)) {
throw new IllegalArgumentException("appid or appsecret not be null!");
}
XStream xstream = new XStream();
xstream.autodetectAnnotations(true);
xstream.processAnnotations(Token.class);
File token_file = new File(String.format("%s/token_%s.xml", ConfigUtil.getValue("token_path"), appid));
Token token = null;
Calendar ca = Calendar.getInstance();
long now_time = ca.getTimeInMillis();
try {
String api_token_uri = String.format(ConfigUtil.getValue("api_token_uri"), appid, appsecret);
Response response = null;
if (token_file.exists()) {
token = (Token) xstream.fromXML(token_file);
long expise_time = token.getTime() + (token.getExpiresIn() * 1000) - 3;
if (expise_time > now_time) {
return token;
}
response = request.get(api_token_uri);
} else {
response = request.get(api_token_uri);
try {
token_file.createNewFile();
} catch (IOException e) {
token_file.getParentFile().mkdirs();
}
}
token = response.getAsObject(Token.class);
token.setTime(now_time);
token.setOpenid(appid);
xstream.toXML(token, new FileOutputStream(token_file));
} catch (IOException e) {
;
}
return token;
}
}

View File

@ -0,0 +1,82 @@
package com.foxinmy.weixin4j.api.token;
import org.jsoup.helper.StringUtil;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.HttpRequest;
import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.util.ConfigUtil;
/**
* 基于redis保存的Token获取类
*
* @className RedisTokenApi
* @author jy.hu
* @date 2014年9月27日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token">获取token说明</a>
* @see com.foxinmy.weixin4j.model.Token
*/
public class RedisTokenApi implements TokenApi {
private final HttpRequest request = new HttpRequest();
private final String appid;
private final String appsecret;
private JedisPool jedisPool;
public RedisTokenApi() {
this(ConfigUtil.getValue("app_id"), ConfigUtil.getValue("app_secret"));
}
public RedisTokenApi(String appid, String appsecret) {
this(appid, appsecret, "localhost", 6379);
}
public RedisTokenApi(String appid, String appsecret, String host, int port) {
this.appid = appid;
this.appsecret = appsecret;
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxTotal(50);
poolConfig.setMaxIdle(5);
poolConfig.setMaxWaitMillis(2000);
poolConfig.setTestOnBorrow(false);
poolConfig.setTestOnReturn(true);
this.jedisPool = new JedisPool(poolConfig, host, port);
}
@Override
public Token getToken() throws WeixinException {
if (StringUtil.isBlank(appid) || StringUtil.isBlank(appsecret)) {
throw new IllegalArgumentException("appid or appsecret not be null!");
}
Token token = null;
Jedis jedis = null;
try {
jedis = jedisPool.getResource();
String key = String.format("token:%s", appid);
String accessToken = jedis.get(key);
if (StringUtil.isBlank(accessToken)) {
String api_token_uri = String.format(ConfigUtil.getValue("api_token_uri"), appid, appsecret);
token = request.get(api_token_uri).getAsObject(Token.class);
jedis.setex(key, token.getExpiresIn() - 3, token.getAccessToken());
} else {
token = new Token();
token.setAccessToken(accessToken);
token.setExpiresIn(jedis.ttl(key).intValue());
}
token.setTime(System.currentTimeMillis());
token.setOpenid(appid);
} catch (Exception e) {
jedisPool.returnBrokenResource(jedis);
} finally {
jedisPool.returnResource(jedis);
}
return token;
}
}

View File

@ -0,0 +1,19 @@
package com.foxinmy.weixin4j.api.token;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token;
/**
* 获取Token接口
*
* @className TokenApi
* @author jy.hu
* @date 2014年9月27日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.model.Token
* @see com.foxinmy.weixin4j.api.token.FileTokenApi
* @see com.foxinmy.weixin4j.api.token.RedisTokenApi
*/
public interface TokenApi {
public Token getToken() throws WeixinException;
}

View File

@ -15,6 +15,7 @@ api_base_url=https://api.weixin.qq.com/cgi-bin
mp_base_url=https://mp.weixin.qq.com/cgi-bin
file_base_url=http://file.api.weixin.qq.com/cgi-bin
# \u7f51\u9875\u6388\u6743\u83b7\u53d6\u7528\u6237\u4fe1\u606f
user_auth_uri=https://open.weixin.qq.com/connect/oauth2/authorize?appid={app_id}&redirect_uri=%s&response_type=code&scope=%s&state=%s#wechat_redirect
sns_user_token_uri=https://api.weixin.qq.com/sns/oauth2/access_token?appid={app_id}&secret={app_secret}&code=%s&grant_type=authorization_code
@ -23,7 +24,7 @@ sns_user_info_uri=https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=
# \u76f4\u63a5\u83b7\u53d6\u7528\u6237\u4fe1\u606f
api_user_info_uri={api_base_url}/user/info?access_token=%s&openid=%s&lang=zh_CN
# \u83b7\u53d6\u6211\u7684token
api_token_uri={api_base_url}/token?grant_type=client_credential&appid={app_id}&secret={app_secret}
api_token_uri={api_base_url}/token?grant_type=client_credential&appid=%s&secret=%s
# \u83b7\u53d6\u4e8c\u7ef4\u7801
qr_ticket_uri={api_base_url}/qrcode/create?access_token=%s
@ -53,14 +54,25 @@ menu_create_uri={api_base_url}/menu/create?access_token=%s
menu_get_uri={api_base_url}/menu/get?access_token=%s
# \u5220\u9664\u83dc\u5355
menu_delete_uri={api_base_url}/menu/delete?access_token=%s
# \u4e0a\u4f20\u6d88\u606f
news_upload_uri={api_base_url}/media/uploadnews?access_token=%s
# \u4e0a\u4f20\u56fe\u6587
article_upload_uri={api_base_url}/media/uploadnews?access_token=%s
# \u4e0a\u4f20\u89c6\u9891
video_upload_uri={file_base_url}/media/uploadvideo?access_token=%s
# \u5206\u7ec4\u7fa4\u53d1
mass_group_uri={api_base_url}/message/mass/sendall?access_token=%s
# openId\u7fa4\u53d1
mass_openid_uri={api_base_url}/message/mass/send?access_token=%s
# \u5220\u9664\u7fa4\u53d1
mass_delete_uri={api_base_url}/message/mass/delete?access_token=%s
# \u5ba2\u670d\u804a\u5929\u8bb0\u5f55
custom_record_uri={api_base_url}/customservice/getrecord?access_token=%s
# \u957f\u94fe\u63a5\u8f6c\u77ed\u94fe\u63a5
shorturl_uri={api_base_url}/shorturl?access_token=%s
# \u8bbe\u7f6e\u5907\u6ce8\u540d
updateremark_uri={api_base_url}/user/info/updateremark?access_token=%s
# \u6a21\u677f\u6d88\u606f
template_send_uri={api_base_url}/message/template/send?access_token=%s
# token\u5b58\u653e\u8def\u5f84
token_path=/tmp/weixin/token

View File

@ -1,53 +1,76 @@
package com.foxinmy.weixin4j.http;
import java.io.IOException;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.cookie.CookiePolicy;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.params.ClientPNames;
import org.apache.http.client.params.CookiePolicy;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.FileEntity;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.impl.client.AbstractHttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.util.EntityUtils;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.msg.BaseResult;
/**
* 调用微信相关接口的HttpRequest,对于其他请求可能并不试用
*
* @className HttpRequest
* @author jy
* @date 2014年8月21日
* @since JDK 1.7
* @see
*/
public class HttpRequest {
private final String CONTENT_CHARSET = "UTF-8";
private final String ERROR_CODE_KEY = "errcode";
private final String ERROR_MSG_KEY = "errmsg";
private HttpClient client;
private AbstractHttpClient client;
public HttpRequest() {
this(150, 30000, 30000, 1024 * 1024);
this(150, 100, 10000, 10000);
}
public HttpRequest(int maxConPerHost, int conTimeOutMs, int soTimeOutMs, int maxSize) {
MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
connectionManager = new MultiThreadedHttpConnectionManager();
HttpConnectionManagerParams params = connectionManager.getParams();
params.setDefaultMaxConnectionsPerHost(maxConPerHost);
params.setConnectionTimeout(conTimeOutMs);
params.setSoTimeout(soTimeOutMs);
public HttpRequest(int maxConPerRoute, int maxTotal, int socketTimeout, int connectionTimeout) {
PoolingClientConnectionManager connectionManager = new PoolingClientConnectionManager();
// 指定IP并发最大数
connectionManager.setDefaultMaxPerRoute(maxConPerRoute);
// socket最大创建数
connectionManager.setMaxTotal(maxTotal);
HttpClientParams clientParams = new HttpClientParams();
clientParams.setCookiePolicy(CookiePolicy.IGNORE_COOKIES);
client = new HttpClient(clientParams, connectionManager);
client.getParams().setParameter(HttpMethodParams.HTTP_CONTENT_CHARSET, CONTENT_CHARSET);
client = new DefaultHttpClient(connectionManager);
client.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT, socketTimeout);
client.getParams().setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, connectionTimeout);
client.getParams().setBooleanParameter(CoreConnectionPNames.TCP_NODELAY, false);
client.getParams().setParameter(CoreConnectionPNames.SOCKET_BUFFER_SIZE, 1024 * 1024);
client.getParams().setParameter(ClientPNames.COOKIE_POLICY, CookiePolicy.IGNORE_COOKIES);
client.getParams().setParameter(CoreProtocolPNames.HTTP_CONTENT_CHARSET, Consts.UTF_8);
client.getParams().setParameter(HttpHeaders.CONTENT_ENCODING, Consts.UTF_8);
client.getParams().setParameter(HttpHeaders.ACCEPT_CHARSET, Consts.UTF_8);
}
public Response get(String url) throws WeixinException {
Parameter[] empty = null;
return get(url, empty);
return get(url, (Parameter[]) null);
}
public Response get(String url, Parameter... parameters) throws WeixinException {
@ -60,70 +83,87 @@ public class HttpRequest {
sb.append(parameters[i].toGetPara());
}
}
return doRequest(new GetMethod(sb.toString()));
return doRequest(new HttpGet(sb.toString()));
}
public Response post(String url) throws WeixinException {
Parameter[] empty = null;
return post(url, empty);
return post(url, (Parameter[]) null);
}
public Response post(String url, Parameter... parameters) throws WeixinException {
PostMethod method = new PostMethod(url);
HttpPost method = new HttpPost(url);
List<NameValuePair> params = new ArrayList<NameValuePair>();
for (Parameter parameter : parameters) {
method.addParameter(parameter.toPostPara());
params.add(parameter.toPostPara());
}
method.setEntity(new UrlEncodedFormEntity(params, Consts.UTF_8));
return doRequest(method);
}
public Response post(String url, String body) throws WeixinException {
HttpPost method = new HttpPost(url);
method.setEntity(new StringEntity(body, ContentType.create(ContentType.APPLICATION_JSON.getMimeType(), Consts.UTF_8)));
return doRequest(method);
}
public Response post(String url, byte[] bytes) throws WeixinException {
HttpPost method = new HttpPost(url);
method.setEntity(new ByteArrayEntity(bytes, ContentType.create(ContentType.MULTIPART_FORM_DATA.getMimeType(), Consts.UTF_8)));
return doRequest(method);
}
public Response post(String url, File file) throws WeixinException {
HttpPost method = new HttpPost(url);
method.setEntity(new FileEntity(file, ContentType.create(ContentType.APPLICATION_OCTET_STREAM.getMimeType(), Consts.UTF_8)));
return doRequest(method);
}
public Response post(String url, PartParameter... paramters) throws WeixinException {
HttpPost method = new HttpPost(url);
MultipartEntity entity = new MultipartEntity();
for (PartParameter paramter : paramters) {
entity.addPart(paramter.getName(), paramter.getContentBody());
}
method.setEntity(entity);
return doRequest(method);
}
public Response post(String url, RequestEntity entity) throws WeixinException {
PostMethod method = new PostMethod(url);
method.setRequestEntity(entity);
return doRequest(method);
}
public Response post(String url, Part... parts) throws WeixinException {
PostMethod method = new PostMethod(url);
method.getParams().setContentCharset(CONTENT_CHARSET);
MultipartRequestEntity entity = new MultipartRequestEntity(parts, method.getParams());
method.setRequestEntity(entity);
return doRequest(method);
}
protected Response doRequest(HttpMethod method) throws WeixinException {
protected Response doRequest(HttpRequestBase request) throws WeixinException {
try {
HttpResponse httpResponse = client.execute(request);
StatusLine statusLine = httpResponse.getStatusLine();
HttpEntity httpEntity = httpResponse.getEntity();
method.getParams().setContentCharset(CONTENT_CHARSET);
method.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(3, false));
int status = client.executeMethod(method);
int status = statusLine.getStatusCode();
if (status != HttpStatus.SC_OK) {
throw new WeixinException(status, "request fail");
}
// HttpClient对于要求接受后继服务的请求象POST和PUT等不能自动处理转发
// 301或者302
if (status == HttpStatus.SC_MOVED_PERMANENTLY || status == HttpStatus.SC_MOVED_TEMPORARILY) {
throw new WeixinException(status, String.format("the page was redirected to %s", method.getResponseHeader("location")));
throw new WeixinException(status, String.format("the page was redirected to %s", httpResponse.getFirstHeader("location")));
}
Response response = new Response(method.getResponseBodyAsString());
response.setBody(method.getResponseBody());
byte[] data = EntityUtils.toByteArray(httpEntity);
Response response = new Response();
response.setBody(data);
response.setStatusCode(status);
response.setStatusText(method.getStatusText());
response.setStream(method.getResponseBodyAsStream());
response.setStatusText(statusLine.getReasonPhrase());
response.setStream(new ByteArrayInputStream(data));
response.setText(StringUtils.newStringUtf8(data));
Header contentType = method.getResponseHeader("Content-Type");
if (contentType.getValue().indexOf("application/json") >= 0 || contentType.getValue().indexOf("text/plain") >= 0) {
JSONObject jsonObj = response.getAsJson();
if (jsonObj.containsKey(ERROR_CODE_KEY) && jsonObj.getIntValue(ERROR_CODE_KEY) != 0) {
throw new WeixinException(jsonObj.getIntValue(ERROR_CODE_KEY), jsonObj.getString(ERROR_MSG_KEY));
Header contentType = httpResponse.getFirstHeader(HttpHeaders.CONTENT_TYPE);
if (contentType.getValue().contains(ContentType.APPLICATION_JSON.getMimeType())) {
BaseResult result = response.getAsResult();
if (result.getErrcode() != 0) {
throw new WeixinException(result.getErrcode(), result.getErrmsg());
}
}
EntityUtils.consume(httpEntity);
return response;
} catch (IOException e) {
} catch (Exception e) {
throw new WeixinException(e.getMessage());
} finally {
method.releaseConnection();
request.releaseConnection();
}
}
}

View File

@ -2,10 +2,15 @@ package com.foxinmy.weixin4j.http;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.http.NameValuePair;
import org.apache.http.message.BasicNameValuePair;
public class Parameter {
private final static String CHARSET = StandardCharsets.UTF_8.name();
private String name;
private String value;
@ -36,7 +41,7 @@ public class Parameter {
public String toGetPara() {
try {
return String.format("&%s=%s", URLEncoder.encode(name, "UTF-8"), URLEncoder.encode(value, "UTF-8"));
return String.format("&%s=%s", name, URLEncoder.encode(value, CHARSET));
} catch (UnsupportedEncodingException e) {
return String.format("&%s=%s", name, value);
}
@ -44,9 +49,9 @@ public class Parameter {
public NameValuePair toPostPara() {
try {
return new NameValuePair(URLEncoder.encode(name, "UTF-8"), URLEncoder.encode(value, "UTF-8"));
return new BasicNameValuePair(name, URLEncoder.encode(value, CHARSET));
} catch (UnsupportedEncodingException e) {
return new NameValuePair(name, value);
return new BasicNameValuePair(name, value);
}
}

View File

@ -0,0 +1,35 @@
package com.foxinmy.weixin4j.http;
import org.apache.http.entity.mime.content.ContentBody;
public class PartParameter {
private String name;
private ContentBody contentBody;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public ContentBody getContentBody() {
return contentBody;
}
public void setContentBody(ContentBody contentBody) {
this.contentBody = contentBody;
}
public PartParameter(String name, ContentBody contentBody) {
super();
this.name = name;
this.contentBody = contentBody;
}
@Override
public String toString() {
return "PartParameter [name=" + name + ", contentBody=" + contentBody + "]";
}
}

View File

@ -11,20 +11,20 @@ import org.dom4j.io.SAXReader;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.WeixinProxy;
import com.foxinmy.weixin4j.msg.ErrorMessage;
import com.foxinmy.weixin4j.msg.BaseResult;
import com.thoughtworks.xstream.XStream;
public class Response {
private final String ERROR_CODE_KEY = "errcode";
private final String ERROR_MSG_KEY = "errmsg";
private String text;
private int statusCode;
private String statusText;
private byte[] body;
private InputStream stream;
public Response() {
}
public Response(String text) {
this.text = text;
}
@ -33,6 +33,10 @@ public class Response {
return text;
}
public BaseResult getAsResult() {
return JSON.parseObject(text, BaseResult.class);
}
public JSONObject getAsJson() {
return JSON.parseObject(text);
}
@ -56,24 +60,17 @@ public class Response {
* @return
* @throws DocumentException
*/
public ErrorMessage getErrorMsg() throws DocumentException {
JSONObject jsonObj = getAsJson();
if (jsonObj.containsKey(ERROR_CODE_KEY)) {
public BaseResult getBaseError() throws DocumentException {
BaseResult result = getAsResult();
if (result.getErrcode() != 0) {
SAXReader reader = new SAXReader();
Document doc = reader.read(WeixinProxy.class
.getResourceAsStream("error.xml"));
Node node = doc.getRootElement().selectSingleNode(
String.format("error[@code='%d']",
jsonObj.getInteger(ERROR_CODE_KEY)));
Document doc = reader.read(WeixinProxy.class.getResourceAsStream("error.xml"));
Node node = doc.getRootElement().selectSingleNode(String.format("error[@code='%d']", result.getErrcode()));
if (node != null) {
return new ErrorMessage(jsonObj.getInteger(ERROR_CODE_KEY),
jsonObj.getString(ERROR_MSG_KEY), node.getStringValue());
result.setText(node.getStringValue());
}
return new ErrorMessage(jsonObj.getInteger(ERROR_CODE_KEY),
"unknown error", "未知错误");
}
return new ErrorMessage(0, "request success", "");
return result;
}
public String getText() {
@ -124,5 +121,4 @@ public class Response {
sb.append(", statusText=").append(statusText).append("]");
return sb.toString();
}
}

View File

@ -4,11 +4,13 @@ import java.io.Serializable;
/**
* 网页授权结果
*
* @className AuthResult
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">网页授权获取用户基本资料</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">网页授权获取用户基本资料</a>
*/
public class AuthResult implements Serializable {
@ -16,11 +18,13 @@ public class AuthResult implements Serializable {
/**
* 网页授权获取code
*
* @className AuthScope
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code">获取code</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%BD%91%E9%A1%B5%E6%8E%88%E6%9D%83%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF#.E7.AC.AC.E4.B8.80.E6.AD.A5.EF.BC.9A.E7.94.A8.E6.88.B7.E5.90.8C.E6.84.8F.E6.8E.88.E6.9D.83.EF.BC.8C.E8.8E.B7.E5.8F.96code">获取code</a>
*/
public enum AuthScope {
BASE("snsapi_base"), USERINFO("snsapi_userinfo");
@ -54,6 +58,11 @@ public class AuthResult implements Serializable {
this.accessToken = accessToken;
}
public AuthResult(String location, AuthCode authCode) {
this.location = location;
this.authCode = authCode;
}
public AuthCode getAuthCode() {
return authCode;
}

View File

@ -5,24 +5,29 @@ import java.util.ArrayList;
import java.util.List;
import com.alibaba.fastjson.annotation.JSONField;
import com.foxinmy.weixin4j.type.ButtonType;
/**
* 菜单按钮
* <p>目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单,一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以"..."代替
* 请注意,创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来,建议测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果</p>
* <p>
* 目前自定义菜单最多包括3个一级菜单,每个一级菜单最多包含5个二级菜单,一级菜单最多4个汉字,二级菜单最多7个汉字,多出来的部分将会以"..."代替
* 请注意,创建自定义菜单后,由于微信客户端缓存,需要24小时微信客户端才会展现出来,建议测试时可以尝试取消关注公众账号后再次关注,则可以看到创建后的效果
* </p>
*
* @className Button
* @author jy.hu
* @date 2014年4月5日
* @since JDK 1.7
* @see com.foxinmy.weixin4j.type.ButtonType
*/
public class Button implements Serializable {
private static final long serialVersionUID = -6422234732203854866L;
private String name;
private BtnType type;
private String key;
private String url;
private ButtonType type; // 菜单的响应动作类型
private String key; // click等点击类型必须
private String url; // view类型必须
@JSONField(name = "sub_button")
private List<Button> subs;
@ -37,7 +42,7 @@ public class Button implements Serializable {
public Button(String name, String url) {
this.name = name;
this.url = url;
this.type = BtnType.view;
this.type = ButtonType.view;
}
public String getName() {
@ -48,11 +53,11 @@ public class Button implements Serializable {
this.name = name;
}
public BtnType getType() {
public ButtonType getType() {
return type;
}
public void setType(BtnType type) {
public void setType(ButtonType type) {
this.type = type;
}
@ -80,26 +85,12 @@ public class Button implements Serializable {
this.subs = subs;
}
public void pushSub(Button btn) {
public Button pushSub(Button btn) {
if (this.subs == null) {
this.subs = new ArrayList<Button>();
}
this.subs.add(btn);
}
/**
* 按钮类型
* <p>click
* 用户点击click类型按钮后微信服务器会通过消息接口推送消息类型为event 的结构给开发者(参考消息接口指南),并且带上按钮中开发者填写的key值,开发者可以通过自定义的key值与用户进行交互</p>
* <p>view
* 用户点击view类型按钮后,微信客户端将会打开开发者在按钮中填写的url值(即网页链接),达到打开网页的目的,建议与网页授权获取用户基本信息接口结合,获得用户的登入个人信息</p>
* @className BtnType
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
*/
public enum BtnType {
click, view
return this;
}
@Override
@ -119,5 +110,4 @@ public class Button implements Serializable {
sb.append("]");
return sb.toString();
}
}

View File

@ -72,7 +72,6 @@ public class CustomRecord implements Serializable {
this.code = code;
this.desc = desc;
}
public int getCode() {
return code;
}

View File

@ -25,6 +25,8 @@ public class MpArticle implements Serializable {
private String url;// 在图文消息页面点击阅读原文后的页面 可为空
private String content;// 图文消息页面的内容支持HTML标签 非空
private String digest;// 图文消息的描述 可为空
@JSONField(name = "show_cover_pic")
private short showCoverPic; // 是否显示封面1为显示0为不显示 可为空
public String getThumbMediaId() {
return thumbMediaId;
}
@ -61,7 +63,12 @@ public class MpArticle implements Serializable {
public void setDigest(String digest) {
this.digest = digest;
}
public short getShowCoverPic() {
return showCoverPic;
}
public void setShowCoverPic(short showCoverPic) {
this.showCoverPic = showCoverPic;
}
public MpArticle(String thumbMediaId, String title, String content) {
this.thumbMediaId = thumbMediaId;
this.title = title;
@ -71,5 +78,16 @@ public class MpArticle implements Serializable {
public MpArticle() {
}
@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();
}
}

View File

@ -7,34 +7,50 @@ import com.thoughtworks.xstream.annotations.XStreamOmitField;
/**
* 二维码参数对象
* <p>目前有2种类型的二维码,分别是临时二维码和永久二维码,前者有过期时间,最大为1800秒,但能够生成较多数量,后者无过期时间,数量较少(目前参数只支持1--100000)</p>
* <p>
* 目前有2种类型的二维码,分别是临时二维码和永久二维码,前者有过期时间,最大为1800秒,但能够生成较多数量,后者无过期时间,数量较少(目前参数只支持1--
* 100000)
* </p>
*
* @className QRParameter
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81">生成带参数的二维码</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E7%94%9F%E6%88%90%E5%B8%A6%E5%8F%82%E6%95%B0%E7%9A%84%E4%BA%8C%E7%BB%B4%E7%A0%81">生成带参数的二维码</a>
*/
public class QRParameter implements Serializable {
private static final long serialVersionUID = 6611187606558274253L;
public enum QRType {
QR_SCENE, // 临时
QR_LIMIT_SCENE; // 永久
TEMPORARY("QR_SCENE"), // 临时
PERMANENCE("QR_LIMIT_SCENE"); // 永久
private String name;
QRType(String name) {
this.name = name;
}
private int expire_seconds; // 该二维码有效时间以秒为单位 最大不超过1800
public String getName() {
return name;
}
}
@XStreamAlias("expire_seconds")
private int expireSeconds; // 该二维码有效时间以秒为单位 最大不超过1800
@XStreamAlias("action_name")
private QRType qrType; // 二维码类型QR_SCENE为临时,QR_LIMIT_SCENE为永久
@XStreamOmitField
private int scene_id; // 场景值ID临时二维码时为32位非0整型永久二维码时最大值为100000目前参数只支持1--100000
@XStreamAlias("scene_id")
private int sceneId; // 场景值ID临时二维码时为32位非0整型永久二维码时最大值为100000目前参数只支持1--100000
public int getExpire_seconds() {
return expire_seconds;
public int getExpireSeconds() {
return expireSeconds;
}
public void setExpire_seconds(int expire_seconds) {
this.expire_seconds = expire_seconds;
public void setExpireSeconds(int expireSeconds) {
this.expireSeconds = expireSeconds;
}
public QRType getQrType() {
@ -45,22 +61,26 @@ public class QRParameter implements Serializable {
this.qrType = qrType;
}
public int getScene_id() {
return scene_id;
public int getSceneId() {
return sceneId;
}
public void setScene_id(int scene_id) {
this.scene_id = scene_id;
public void setSceneId(int sceneId) {
this.sceneId = sceneId;
}
public QRParameter(int expire_seconds, QRType qrType, int scene_id) {
this.expire_seconds = expire_seconds;
public QRParameter(int expireSeconds, QRType qrType, int sceneId) {
this.expireSeconds = expireSeconds;
this.qrType = qrType;
this.scene_id = scene_id;
this.sceneId = sceneId;
}
public QRParameter(QRType action_name, int scene_id) {
this(0, action_name, scene_id);
public QRParameter(QRType qrType, int sceneId) {
this(0, qrType, sceneId);
}
public QRParameter(int sceneId, int expireSeconds) {
this(0, null, sceneId);
}
public String toJson() {
@ -74,17 +94,17 @@ public class QRParameter implements Serializable {
* "expire_seconds"); } return xstream.toXML(this);
*/
StringBuilder jsonBuilder = new StringBuilder("{");
jsonBuilder.append("\"action_name\":\"").append(qrType.name()).append("\"");
if (this.qrType == QRType.QR_SCENE) {
jsonBuilder.append(",\"expire_seconds\":").append(expire_seconds);
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}}", scene_id));
jsonBuilder.append(",\"action_info\":").append(String.format("{\"scene\": {\"scene_id\": %d}}", sceneId));
jsonBuilder.append("}");
return jsonBuilder.toString();
}
@Override
public String toString() {
return String.format("[QRParameter action_name=%s, expire_seconds=%d, scene_id=%d]", getQrType().name(), getExpire_seconds(), getScene_id());
return "QRParameter [expireSeconds=" + expireSeconds + ", qrType=" + qrType + ", sceneId=" + sceneId + "]";
}
}

View File

@ -2,10 +2,12 @@ package com.foxinmy.weixin4j.model;
import java.io.Serializable;
import com.alibaba.fastjson.annotation.JSONField;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token,正常情况下access_token有效期为7200秒,重复获取将导致上次获取的access_token失效
* access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token,正常情况下access_token有效期为7200秒,
* 重复获取将导致上次获取的access_token失效
*
* @className Token
* @author jy.hu
@ -18,25 +20,27 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
public class Token implements Serializable {
private static final long serialVersionUID = 1L;
private String access_token;
private int expires_in;
@JSONField(name = "access_token")
private String accessToken;
@JSONField(name = "expires_in")
private int expiresIn;
private String openid;
private long time;
public String getAccess_token() {
return access_token;
public String getAccessToken() {
return accessToken;
}
public void setAccess_token(String access_token) {
this.access_token = access_token;
public void setAccessToken(String accessToken) {
this.accessToken = accessToken;
}
public int getExpires_in() {
return expires_in;
public int getExpiresIn() {
return expiresIn;
}
public void setExpires_in(int expires_in) {
this.expires_in = expires_in;
public void setExpiresIn(int expiresIn) {
this.expiresIn = expiresIn;
}
public String getOpenid() {
@ -58,18 +62,13 @@ public class Token implements Serializable {
@Override
public boolean equals(Object obj) {
if (obj instanceof Token) {
return access_token.equals(((Token) obj).getAccess_token());
return accessToken.equals(((Token) obj).getAccessToken());
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[Token access_token=").append(access_token);
sb.append(", expires_in=").append(expires_in);
sb.append(", openid=").append(openid);
sb.append(", time=").append(time).append("]");
return sb.toString();
return "Token [accessToken=" + accessToken + ", expiresIn=" + expiresIn + ", openid=" + openid + ", time=" + time + "]";
}
}

View File

@ -2,15 +2,19 @@ package com.foxinmy.weixin4j.model;
import java.io.Serializable;
import com.foxinmy.weixin4j.util.WeixinUtil;
import org.jsoup.helper.StringUtil;
/**
* 用户对象
* <p>当用户与公众号有交互时,可通过openid获取信息</p>
* <p>
* 当用户与公众号有交互时,可通过openid获取信息
* </p>
*
* @author jy.hu
* @date 2014年4月8日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">获取用户基本资料</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%94%A8%E6%88%B7%E5%9F%BA%E6%9C%AC%E4%BF%A1%E6%81%AF">获取用户基本资料</a>
*/
public class User implements Serializable {
@ -27,6 +31,7 @@ public class User implements Serializable {
private int subscribe; // 是否关注
private long subscribe_time; // 关注时间
private Lang language; // 使用语言
private String unionid; // 只有在用户将公众号绑定到微信开放平台帐号后才会出现该字段
// 国家地区语言版本
public enum Lang {
@ -135,9 +140,10 @@ public class User implements Serializable {
}
public String getHeadimgurl(Size size) {
if (!WeixinUtil.isBlank(headimgurl)) {
if (!StringUtil.isBlank(headimgurl)) {
StringBuilder sb = new StringBuilder(headimgurl);
return sb.replace(0, (headimgurl.length() - 1), size.getInt() + "").toString();
return sb.replace(0, (headimgurl.length() - 1), size.getInt() + "")
.toString();
}
return "";
}
@ -178,6 +184,14 @@ public class User implements Serializable {
this.subscribe_time = subscribe_time;
}
public String getUnionid() {
return unionid;
}
public void setUnionid(String unionid) {
this.unionid = unionid;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof User) {
@ -199,6 +213,7 @@ public class User implements Serializable {
sb.append(", privilege=").append(privilege);
sb.append(", language=").append(language);
sb.append(", subscribe_time=").append(subscribe_time);
sb.append(", unionid=").append(unionid);
sb.append(", subscribe=").append(subscribe).append("]");
return sb.toString();
}

View File

@ -1,7 +1,10 @@
package com.foxinmy.weixin4j.model;
import com.alibaba.fastjson.annotation.JSONField;
/**
* 用户token 一般通过授权页面获得
*
* @className UserToken
* @author jy.hu
* @date 2014年4月6日
@ -13,16 +16,17 @@ public class UserToken extends Token {
private static final long serialVersionUID = 1L;
private String refresh_token;
@JSONField(name = "refresh_token")
private String refreshToken;
private String scope;
public String getRefresh_token() {
return refresh_token;
public String getRefreshToken() {
return refreshToken;
}
public void setRefresh_token(String refresh_token) {
this.refresh_token = refresh_token;
public void setRefreshToken(String refreshToken) {
this.refreshToken = refreshToken;
}
public String getScope() {
@ -35,13 +39,6 @@ public class UserToken extends Token {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[UserToken access_token=").append(super.getAccess_token());
sb.append(", expires_in=").append(super.getExpires_in());
sb.append(", openid=").append(super.getOpenid());
sb.append(", refresh_token=").append(refresh_token);
sb.append(", scope=").append(scope);
sb.append(", time=").append(super.getTime()).append("]");
return sb.toString();
return "UserToken [refreshToken=" + refreshToken + ", scope=" + scope + ", getAccessToken()=" + getAccessToken() + ", getExpiresIn()=" + getExpiresIn() + ", getOpenid()=" + getOpenid() + ", getTime()=" + getTime() + "]";
}
}

View File

@ -4,8 +4,6 @@ import java.io.Serializable;
import java.io.Writer;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.util.WeixinConfig;
import com.foxinmy.weixin4j.util.WeixinUtil;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
@ -14,8 +12,11 @@ import com.thoughtworks.xstream.io.json.JsonWriter;
/**
* 普通消息基类
* <p><font color="red">回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,
* 假如服务器无法保证在五秒内处理并回复可以直接回复空串微信服务器不会对此作任何处理并且不会发起重试</font></p>
* <p>
* <font color="red">回复图片等多媒体消息时需要预先上传多媒体文件到微信服务器,
* 假如服务器无法保证在五秒内处理并回复可以直接回复空串微信服务器不会对此作任何处理并且不会发起重试</font>
* </p>
*
* @className BaseMessage
* @author jy.hu
* @date 2014年4月6日
@ -24,6 +25,7 @@ import com.thoughtworks.xstream.io.json.JsonWriter;
public class BaseMessage implements Serializable {
private static final long serialVersionUID = 7761192742840031607L;
private static XStream xstream;
@XStreamAlias("ToUserName")
private String toUserName; // 开发者微信号
@ -36,10 +38,25 @@ public class BaseMessage implements Serializable {
@XStreamAlias("MsgId")
private long msgId; // 消息ID
static{
xstream = new XStream();
}
public BaseMessage(MessageType msgType) {
this.msgType = msgType;
}
public BaseMessage(MessageType msgType, BaseMessage inMessage) {
this(msgType, inMessage.getFromUserName(), inMessage.getToUserName());
}
public BaseMessage(MessageType msgType, String toUserName,
String fromUserName) {
this.msgType = msgType;
this.toUserName = toUserName;
this.fromUserName = fromUserName;
}
public String getToUserName() {
return toUserName;
}
@ -88,24 +105,34 @@ public class BaseMessage implements Serializable {
return false;
}
protected XStream getXStream() {
Class<? extends BaseMessage> targetClass = getMsgType()
.getMessageClass();
xstream.alias("xml", targetClass);
xstream.autodetectAnnotations(true);
xstream.processAnnotations(targetClass);
xstream.omitField(BaseMessage.class, "msgId");
return xstream;
}
/**
* 消息对象转换为微信服务器接受的xml格式消息
*
* @return xml字符串
*/
public String toXml() {
XStream xstream = new XStream();
xstream.alias("xml", getMsgType().getMessageClass());
Class<? extends BaseMessage> targetClass = getMsgType()
.getMessageClass();
xstream.alias("xml", targetClass);
xstream.autodetectAnnotations(true);
xstream.processAnnotations(getMsgType().getMessageClass());
xstream.processAnnotations(targetClass);
xstream.omitField(BaseMessage.class, "msgId");
if (WeixinUtil.isBlank(fromUserName)) {
setFromUserName(WeixinConfig.getValue("app_openId"));
}
return xstream.toXML(this);
}
/**
* 消息对象转换为微信服务器接受的json格式字符串
*
* @return json字符串
*/
public String toJson() {
@ -118,9 +145,6 @@ public class BaseMessage implements Serializable {
xstream.autodetectAnnotations(true);
xstream.processAnnotations(getMsgType().getMessageClass());
xstream.omitField(BaseMessage.class, "msgId");
if (WeixinUtil.isBlank(fromUserName)) {
setFromUserName(WeixinConfig.getValue("app_openId"));
}
return xstream.toXML(this);
}
}

View File

@ -0,0 +1,78 @@
package com.foxinmy.weixin4j.msg;
import java.io.Serializable;
/**
* 调用接口响应值
*
* @className BaseResult
* @author jy.hu
* @date 2014年9月24日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%85%A8%E5%B1%80%E8%BF%94%E5%9B%9E%E7%A0%81%E8%AF%B4%E6%98%8E">全局返回码</a>
*/
public class BaseResult implements Serializable {
private static final long serialVersionUID = -6185313616955051150L;
private int errcode;
private String errmsg;
private String msgid;
private String text;
public BaseResult() {
}
public BaseResult(int errcode, String errmsg, String text) {
this.errcode = errcode;
this.errmsg = errmsg;
this.text = text;
}
public BaseResult(int errcode, String errmsg, String msgid, String text) {
this.errcode = errcode;
this.errmsg = errmsg;
this.msgid = msgid;
this.text = text;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public int getErrcode() {
return errcode;
}
public void setErrcode(int errcode) {
this.errcode = errcode;
}
public String getErrmsg() {
return errmsg;
}
public void setErrmsg(String errmsg) {
this.errmsg = errmsg;
}
public String getMsgid() {
return msgid;
}
public void setMsgid(String msgid) {
this.msgid = msgid;
}
@Override
public String toString() {
return "BaseResult [errcode=" + errcode + ", errmsg=" + errmsg
+ ", msgid=" + msgid + ", text=" + text + "]";
}
}

View File

@ -1,54 +0,0 @@
package com.foxinmy.weixin4j.msg;
import java.io.Serializable;
public class ErrorMessage implements Serializable {
private static final long serialVersionUID = 2539772564331987708L;
private int code;
private String msg;
private String text;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
public ErrorMessage(int code, String msg, String text) {
this.code = code;
this.msg = msg;
this.text = text;
}
public ErrorMessage() {
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[ErrorMessage code=").append(code);
sb.append(", msg=").append(msg);
sb.append(", text=").append(text).append("]");
return sb.toString();
}
}

View File

@ -5,12 +5,15 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 文本消息(接收|回复)
*
* @className TextMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">接收文本消息</a>
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">回复文本消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">接收文本消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">回复文本消息</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
*/
@ -22,9 +25,8 @@ public class TextMessage extends BaseMessage {
super(MessageType.text);
}
public TextMessage(String toUserName, String content) {
super(MessageType.text);
setToUserName(toUserName);
public TextMessage(String content, BaseMessage inMessage) {
super(MessageType.text, inMessage);
this.content = content;
}

View File

@ -3,16 +3,15 @@ package com.foxinmy.weixin4j.msg.event;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 上报地理位置事件
*
* @className LocationEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E4.B8.8A.E6.8A.A5.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E4.BA.8B.E4.BB.B6">上报地理位置事件</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E4.B8.8A.E6.8A.A5.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E4.BA.8B.E4.BB.B6">上报地理位置事件</a>
*/
public class LocationEventMessage extends EventMessage {
@ -33,30 +32,19 @@ public class LocationEventMessage extends EventMessage {
return latitude;
}
public void setLatitude(String latitude) {
this.latitude = latitude;
}
public String getLongitude() {
return longitude;
}
public void setLongitude(String longitude) {
this.longitude = longitude;
}
public String getPrecision() {
return precision;
}
public void setPrecision(String precision) {
this.precision = precision;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[LocationEventMessage ,toUserName=").append(super.getToUserName());
sb.append("[LocationEventMessage ,toUserName=").append(
super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,eventType=").append(super.getEventType().name());

View File

@ -18,7 +18,7 @@ public class MassEventMessage extends EventMessage {
private static final long serialVersionUID = -1660543255873723895L;
public MassEventMessage() {
super(EventType.MASSSENDJOBFINISH);
super(EventType.massendjobfinish);
}
@XStreamAlias("Status")
@ -35,38 +35,28 @@ public class MassEventMessage extends EventMessage {
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public int getTotalCount() {
return totalCount;
}
public void setTotalCount(int totalCount) {
this.totalCount = totalCount;
}
public int getFilterCount() {
return filterCount;
}
public void setFilterCount(int filterCount) {
this.filterCount = filterCount;
}
public int getSentCount() {
return sentCount;
}
public void setSentCount(int sentCount) {
this.sentCount = sentCount;
}
public int getErrorCount() {
return errorCount;
}
public void setErrorCount(int errorCount) {
this.errorCount = errorCount;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[MassEventMessage ,toUserName=").append(super.getToUserName());
sb.append("[MassEventMessage ,toUserName=").append(
super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,eventType=").append(super.getEventType().name());

View File

@ -3,14 +3,14 @@ package com.foxinmy.weixin4j.msg.event;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 扫描事件
* 扫描二维码事件
*
* @className ScanEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E6.89.AB.E6.8F.8F.E5.B8.A6.E5.8F.82.E6.95.B0.E4.BA.8C.E7.BB.B4.E7.A0.81.E4.BA.8B.E4.BB.B6">扫描二维码事件</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E6.89.AB.E6.8F.8F.E5.B8.A6.E5.8F.82.E6.95.B0.E4.BA.8C.E7.BB.B4.E7.A0.81.E4.BA.8B.E4.BB.B6">扫描二维码事件</a>
*/
public class ScanEventMessage extends EventMessage {
@ -30,18 +30,10 @@ public class ScanEventMessage extends EventMessage {
return eventKey;
}
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
public String getTicket() {
return ticket;
}
public void setTicket(String ticket) {
this.ticket = ticket;
}
public String getParameter() {
return eventKey.replace(PARA_PREFIX, "");
}
@ -49,7 +41,8 @@ public class ScanEventMessage extends EventMessage {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[ScanEventMessage ,toUserName=").append(super.getToUserName());
sb.append("[ScanEventMessage ,toUserName=").append(
super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,eventType=").append(super.getEventType().name());

View File

@ -9,8 +9,6 @@ package com.foxinmy.weixin4j.msg.event;
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E5.85.B3.E6.B3.A8.2F.E5.8F.96.E6.B6.88.E5.85.B3.E6.B3.A8.E4.BA.8B.E4.BB.B6">关注/取消关注事件</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
*/
public class ScribeEventMessage extends ScanEventMessage {

View File

@ -0,0 +1,35 @@
package com.foxinmy.weixin4j.msg.event;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 模板消息事件推送
*
* @className TemplatesendjobfinishMessage
* @author jy
* @date 2014年9月19日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%A8%A1%E6%9D%BF%E6%B6%88%E6%81%AF%E6%8E%A5%E5%8F%A3">模板消息事件推送</a>
*/
public class TemplatesendjobfinishMessage extends EventMessage {
private static final long serialVersionUID = -2903359365988594012L;
public TemplatesendjobfinishMessage() {
super(EventType.templatesendjobfinish);
}
@XStreamAlias("Status")
private String status; // 推送状态
public String getStatus() {
return status;
}
@Override
public String toString() {
return "TemplatesendjobfinishMessage [status=" + status + "]";
}
}

View File

@ -1,17 +1,18 @@
package com.foxinmy.weixin4j.msg.event;
package com.foxinmy.weixin4j.msg.event.menu;
import com.foxinmy.weixin4j.msg.event.EventMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 自定义菜单事件
* 自定义菜单事件(view|click)
*
* @className MenuEventMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E8.87.AA.E5.AE.9A.E4.B9.89.E8.8F.9C.E5.8D.95.E4.BA.8B.E4.BB.B6">自定义菜单事件</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#.E7.82.B9.E5.87.BB.E8.8F.9C.E5.8D.95.E6.8B.89.E5.8F.96.E6.B6.88.E6.81.AF.E6.97.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">菜单事件</a>
*/
public class MenuEventMessage extends EventMessage {
@ -28,14 +29,11 @@ public class MenuEventMessage extends EventMessage {
return eventKey;
}
public void setEventKey(String eventKey) {
this.eventKey = eventKey;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[MenuEventMessage ,toUserName=").append(super.getToUserName());
sb.append("[MenuEventMessage ,toUserName=").append(
super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,eventType=").append(super.getEventType().name());

View File

@ -0,0 +1,74 @@
package com.foxinmy.weixin4j.msg.event.menu;
import com.foxinmy.weixin4j.type.EventType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 弹出地理位置选择器的事件推送
*
* @className MenuLocationEventMessage
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#location_select.EF.BC.9A.E5.BC.B9.E5.87.BA.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E9.80.89.E6.8B.A9.E5.99.A8.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">弹出地理位置选择事件推送</a>
*/
public class MenuLocationEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 145223888272819563L;
public MenuLocationEventMessage() {
super.setEventType(EventType.location_select);
}
@XStreamAlias("SendLocationInfo")
private LocationInfo locationInfo;
public LocationInfo getLocationInfo() {
return locationInfo;
}
public static class LocationInfo {
@XStreamAlias("Location_X")
private double x; // 地理位置维度
@XStreamAlias("Location_Y")
private double y; // 地理位置经度
@XStreamAlias("Scale")
private double scale; // 地图缩放大小
@XStreamAlias("Label")
private String label; // 地理位置信息
@XStreamAlias("Poiname")
private String poiname;
public double getX() {
return x;
}
public double getY() {
return y;
}
public double getScale() {
return scale;
}
public String getLabel() {
return label;
}
public String getPoiname() {
return poiname;
}
@Override
public String toString() {
return "LocationInfo [x=" + x + ", y=" + y + ", scale=" + scale
+ ", label=" + label + ", poiname=" + poiname + "]";
}
}
@Override
public String toString() {
return "MenuLocationEventMessage [locationInfo=" + locationInfo + "]";
}
}

View File

@ -0,0 +1,63 @@
package com.foxinmy.weixin4j.msg.event.menu;
import java.util.List;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 弹出拍照或者相册发图的事件推送(pic_sysphoto|pic_photo_or_album|pic_weixin)
*
* @className MenuPhotoEventMessage
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#pic_sysphoto.EF.BC.9A.E5.BC.B9.E5.87.BA.E7.B3.BB.E7.BB.9F.E6.8B.8D.E7.85.A7.E5.8F.91.E5.9B.BE.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">弹出系统拍照发图的事件推送</a>
*/
public class MenuPhotoEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 3142350663022709730L;
@XStreamAlias("SendPicsInfo")
private PictureInfo pictureInfo;
public PictureInfo getPictureInfo() {
return pictureInfo;
}
public static class PictureInfo {
@XStreamAlias("Count")
private int count;
@XStreamAlias("PicList")
private List<PictureItem> items;
public int getCount() {
return count;
}
public List<PictureItem> getItems() {
return items;
}
@Override
public String toString() {
return "PictureInfo [count=" + count + ", items=" + items + "]";
}
}
@XStreamAlias("item")
public static class PictureItem {
@XStreamAlias("PicMd5Sum")
private String md5;
@Override
public String toString() {
return "PictureItem [md5=" + md5 + "]";
}
}
@Override
public String toString() {
return "MenuPhotoEventMessage [pictureInfo=" + pictureInfo + "]";
}
}

View File

@ -0,0 +1,51 @@
package com.foxinmy.weixin4j.msg.event.menu;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 扫码推事件(scancode_push|scancode_waitmsg)
*
* @className MenuScanPushEventMessage
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81#scancode_push.EF.BC.9A.E6.89.AB.E7.A0.81.E6.8E.A8.E4.BA.8B.E4.BB.B6.E7.9A.84.E4.BA.8B.E4.BB.B6.E6.8E.A8.E9.80.81">扫码推事件的事件推送</a>
*/
public class MenuScanEventMessage extends MenuEventMessage {
private static final long serialVersionUID = 3142350663022709730L;
@XStreamAlias("ScanCodeInfo")
private ScanInfo scanInfo;
public ScanInfo getScanInfo() {
return scanInfo;
}
public static class ScanInfo {
@XStreamAlias("ScanType")
private String type;
@XStreamAlias("ScanResult")
private String result;
public String getType() {
return type;
}
public String getResult() {
return result;
}
@Override
public String toString() {
return "ScanInfo [type=" + type + ", result=" + result + "]";
}
}
@Override
public String toString() {
return "MenuScanPushEventMessage [scanInfo=" + scanInfo + "]";
}
}

View File

@ -6,13 +6,13 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 图片消息
*
* @className ImageMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">图片消息</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">图片消息</a>
*/
public class ImageMessage extends BaseMessage {
@ -31,18 +31,10 @@ public class ImageMessage extends BaseMessage {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View File

@ -6,13 +6,13 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 链接消息
*
* @className LinkMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E9.93.BE.E6.8E.A5.E6.B6.88.E6.81.AF">链接消息</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E9.93.BE.E6.8E.A5.E6.B6.88.E6.81.AF">链接消息</a>
*/
public class LinkMessage extends BaseMessage {
@ -33,26 +33,14 @@ public class LinkMessage extends BaseMessage {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View File

@ -6,13 +6,13 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 地理位置消息
*
* @className LocationMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E6.B6.88.E6.81.AF">地理位置消息</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E5.9C.B0.E7.90.86.E4.BD.8D.E7.BD.AE.E6.B6.88.E6.81.AF">地理位置消息</a>
*/
public class LocationMessage extends BaseMessage {
@ -23,38 +23,26 @@ public class LocationMessage extends BaseMessage {
}
@XStreamAlias("Location_X")
private String location_X; // 地理位置维度
private double x; // 地理位置维度
@XStreamAlias("Location_Y")
private String location_Y; // 地理位置经度
private double y; // 地理位置经度
@XStreamAlias("Scale")
private String scale; // 地图缩放大小
private double scale; // 地图缩放大小
@XStreamAlias("Label")
private String label; // 地理位置信息
public String getLocation_X() {
return location_X;
public double getX() {
return x;
}
public void setLocation_X(String location_X) {
this.location_X = location_X;
public double getY() {
return y;
}
public String getLocation_Y() {
return location_Y;
}
public void setLocation_Y(String location_Y) {
this.location_Y = location_Y;
}
public String getScale() {
public double getScale() {
return scale;
}
public void setScale(String scale) {
this.scale = scale;
}
public String getLabel() {
return label;
}
@ -66,11 +54,12 @@ public class LocationMessage extends BaseMessage {
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[LocationMessage ,toUserName=").append(super.getToUserName());
sb.append("[LocationMessage ,toUserName=")
.append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,location_X=").append(location_X);
sb.append(" ,location_Y=").append(location_Y);
sb.append(" ,location_X=").append(x);
sb.append(" ,location_Y=").append(y);
sb.append(" ,scale=").append(scale);
sb.append(" ,label=").append(label);
sb.append(" ,createTime=").append(super.getCreateTime());

View File

@ -6,13 +6,13 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 视频消息
*
* @className VideoMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">视频消息</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">视频消息</a>
*/
public class VideoMessage extends BaseMessage {
@ -31,18 +31,10 @@ public class VideoMessage extends BaseMessage {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getThumbMediaId() {
return thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View File

@ -6,14 +6,16 @@ import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 语音消息
* <p>开通语音识别功能,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,赋值到Recongnition字段.</p>
* <p>
* 开通语音识别功能,用户每次发送语音给公众号时,微信会在推送的语音消息XML数据包中,赋值到Recongnition字段.
* </p>
*
* @className VoiceMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">语音消息</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF#.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">语音消息</a>
*/
public class VoiceMessage extends BaseMessage {
@ -35,26 +37,14 @@ public class VoiceMessage extends BaseMessage {
return recognition;
}
public void setRecognition(String recognition) {
this.recognition = recognition;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getFormat() {
return format;
}
public void setFormat(String format) {
this.format = format;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();

View File

@ -0,0 +1,75 @@
package com.foxinmy.weixin4j.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 图文对象
*
* @className Article
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Article extends BaseMsg {
private static final long serialVersionUID = 1L;
private String title; // 图文消息标题
@XStreamAlias("description")
private String desc; // 图文消息描述
@XStreamAlias("picurl")
private String picUrl; // 图片链接支持JPGPNG格式较好的效果为大图360*200小图200*200
private String url; // 点击图文消息跳转链接
public Article(String title, String desc, String picUrl, String url) {
this.title = title;
this.desc = desc;
this.picUrl = picUrl;
this.url = url;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getPicUrl() {
return picUrl;
}
public void setPicUrl(String picUrl) {
this.picUrl = picUrl;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
@Override
public String toString() {
return "Article [title=" + title + ", desc=" + desc + ", picUrl="
+ picUrl + ", url=" + url + "]";
}
@Override
public MediaType getMediaType() {
return MediaType.mpnews;
}
}

View File

@ -0,0 +1,33 @@
package com.foxinmy.weixin4j.msg.model;
import java.io.Serializable;
import java.io.Writer;
import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;
public abstract class BaseMsg implements Serializable {
private static final long serialVersionUID = 1L;
public abstract MediaType getMediaType();
/**
* 客服消息json化,适用于客服消息接口
*
* @return {"touser": "to","msgtype": "text","text": {"content": "123"}}
*/
public String toNotifyJson() {
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);
xstream.processAnnotations(this.getClass());
return xstream.toXML(this);
}
}

View File

@ -0,0 +1,38 @@
package com.foxinmy.weixin4j.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 图片对象
*
* @className Image
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Image extends BaseMsg {
private static final long serialVersionUID = 1L;
@XStreamAlias("media_id")
private String mediaId;
public Image(String mediaId) {
this.mediaId = mediaId;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
@Override
public MediaType getMediaType() {
return MediaType.image;
}
}

View File

@ -0,0 +1,93 @@
package com.foxinmy.weixin4j.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 音乐对象
*
* @className Music
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Music extends BaseMsg {
private static final long serialVersionUID = 1L;
private String title;
@XStreamAlias("description")
private String desc;
@XStreamAlias("musicurl")
private String musicUrl;
@XStreamAlias("hqmusicurl")
private String hqMusicUrl;
@XStreamAlias("thumb_media_id")
private String thumbMediaId;
public Music(String thumbMediaId) {
this(null, null, null, null, thumbMediaId);
}
public Music(String title, String desc, String musicUrl, String hqMusicUrl,
String thumbMediaId) {
this.title = title;
this.desc = desc;
this.musicUrl = musicUrl;
this.hqMusicUrl = hqMusicUrl;
this.thumbMediaId = thumbMediaId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
public String getMusicUrl() {
return musicUrl;
}
public void setMusicUrl(String musicUrl) {
this.musicUrl = musicUrl;
}
public String getHqMusicUrl() {
return hqMusicUrl;
}
public void setHqMusicUrl(String hqMusicUrl) {
this.hqMusicUrl = hqMusicUrl;
}
public String getThumbMediaId() {
return thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
@Override
public String toString() {
return "Music [title=" + title + ", desc=" + desc + ", musicUrl="
+ musicUrl + ", hqMusicUrl=" + hqMusicUrl + ", thumbMediaId="
+ thumbMediaId + "]";
}
@Override
public MediaType getMediaType() {
return MediaType.music;
}
}

View File

@ -0,0 +1,40 @@
package com.foxinmy.weixin4j.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 文本对象
* @className Text
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Text extends BaseMsg {
private static final long serialVersionUID = 1L;
private String content;
public String getContent() {
return content;
}
public void setContent(String content) {
this.content = content;
}
public Text(String content) {
this.content = content;
}
@Override
public String toString() {
return "Text [content=" + content + "]";
}
@Override
public MediaType getMediaType() {
return MediaType.text;
}
}

View File

@ -0,0 +1,88 @@
package com.foxinmy.weixin4j.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 视频对象
*
* @className Video
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Video extends BaseMsg {
private static final long serialVersionUID = 1L;
@XStreamAlias("media_id")
private String mediaId;
@XStreamAlias("thumb_media_id")
private String thumbMediaId;
private String title;
@XStreamAlias("description")
private String desc;
public Video(String mediaId) {
this(mediaId, null, null, null);
}
public Video(String mediaId, String thumbMediaId) {
this(mediaId, thumbMediaId, null, null);
}
public Video(String mediaId, String title, String desc) {
this(mediaId, null, title, desc);
}
public Video(String mediaId, String thumbMediaId, String title, String desc) {
this.mediaId = mediaId;
this.thumbMediaId = thumbMediaId;
this.title = title;
this.desc = desc;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
public String getThumbMediaId() {
return thumbMediaId;
}
public void setThumbMediaId(String thumbMediaId) {
this.thumbMediaId = thumbMediaId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "Video [mediaId=" + mediaId + ", thumbMediaId=" + thumbMediaId
+ ", title=" + title + ", desc=" + desc + "]";
}
@Override
public MediaType getMediaType() {
return MediaType.vedio;
}
}

View File

@ -0,0 +1,38 @@
package com.foxinmy.weixin4j.msg.model;
import com.foxinmy.weixin4j.type.MediaType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 语音对象
*
* @className Image
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class Voice extends BaseMsg {
private static final long serialVersionUID = 1L;
@XStreamAlias("media_id")
private String mediaId;
public Voice(String mediaId) {
this.mediaId = mediaId;
}
public String getMediaId() {
return mediaId;
}
public void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
@Override
public MediaType getMediaType() {
return MediaType.voice;
}
}

View File

@ -3,17 +3,21 @@ package com.foxinmy.weixin4j.msg.notify;
import java.util.LinkedList;
import java.util.List;
import com.foxinmy.weixin4j.msg.model.Article;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
/**
* 客服图文消息
*
* @className ArticleNotify
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF">客服图文消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF">客服图文消息</a>
* @see com.foxinmy.weixin.msg.model.Article
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify#toJson()
*/
@ -46,60 +50,53 @@ public class ArticleNotify extends BaseNotify {
count++;
}
public void pushAll(List<Article> articles) {
count = articles.size();
if (articles.size() > MAX_ARTICLE_COUNT) {
count = MAX_ARTICLE_COUNT;
articles = articles.subList(0, count);
}
if (this.news == null) {
this.news = new News();
}
this.news.setArticles(articles);
}
private static class News {
@XStreamAlias("articles")
private List<$> articles;
private List<Article> articles;
public News() {
this.articles = new LinkedList<$>();
this.articles = new LinkedList<Article>();
}
public void pushArticle(String title, String desc, String picUrl, String url) {
this.articles.add(new $(title, desc, picUrl, url));
public void pushArticle(String title, String desc, String picUrl,
String url) {
this.articles.add(new Article(title, desc, picUrl, url));
}
public void setArticles(List<Article> articles) {
this.articles = articles;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
for ($ item : articles) {
sb.append("{title=").append(item.title);
sb.append(" ,description=").append(item.desc);
sb.append(" ,picUrl=").append(item.picUrl);
sb.append(" ,url=").append(item.url).append("}");
for (Article article : articles) {
sb.append("{title=").append(article.getTitle());
sb.append(" ,description=").append(article.getDesc());
sb.append(" ,picUrl=").append(article.getPicUrl());
sb.append(" ,url=").append(article.getUrl()).append("}");
}
return sb.toString();
}
}
private static class $ {
private String title; // 图文消息标题
@XStreamAlias("description")
private String desc; // 图文消息描述
@XStreamAlias("picurl")
private String picUrl; // 图片链接支持JPGPNG格式较好的效果为大图360*200小图200*200
@XStreamAlias("url")
private String url; // 点击图文消息跳转链接
public $(String title, String desc, String picUrl, String url) {
this.title = title;
this.desc = desc;
this.picUrl = picUrl;
this.url = url;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(article ,title=").append(title);
sb.append(" ,description=").append(desc);
sb.append(" ,picUrl=").append(picUrl);
sb.append(" ,url=").append(url).append(")");
return sb.toString();
}
}
@Override
public String toString() {
return String.format("[ArticleNotify touser=%s ,msgtype=%s ,articles=%s]", super.getTouser(), super.getMsgtype().name(), this.news.toString());
return String.format(
"[ArticleNotify touser=%s ,msgtype=%s ,articles=%s]",
super.getTouser(), super.getMsgtype().name(),
this.news.toString());
}
}

View File

@ -1,14 +1,17 @@
package com.foxinmy.weixin4j.msg.notify;
import com.foxinmy.weixin4j.msg.model.Image;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 客服图片消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">客服图片消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">客服图片消息</a>
* @see com.foxinmy.weixin4j.msg.model.Image
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify#toJson()
*/
@ -20,30 +23,25 @@ public class ImageNotify extends BaseNotify {
super(MessageType.image);
}
public ImageNotify(String mediaId) {
super(MessageType.image);
this.image = new $(mediaId);
public ImageNotify(String touser) {
super(touser, MessageType.image);
}
public ImageNotify(String mediaId, String touser) {
super(touser, MessageType.image);
this.image = new $(mediaId);
this.pushMediaId(mediaId);
}
@XStreamAlias("image")
private $ image;
private static class $ {
@XStreamAlias("media_id")
private String mediaId;
public $(String mediaId) {
this.mediaId = mediaId;
}
public void pushMediaId(String mediaId) {
this.image = new Image(mediaId);
}
private Image image;
@Override
public String toString() {
return String.format("[ImageNotify touser=%s ,msgtype=%s ,mediaId=%s]", super.getTouser(), super.getMsgtype().name(), this.image.mediaId);
return String.format("[ImageNotify touser=%s ,msgtype=%s ,mediaId=%s]",
super.getTouser(), super.getMsgtype().name(),
this.image.getMediaId());
}
}

View File

@ -1,14 +1,17 @@
package com.foxinmy.weixin4j.msg.notify;
import com.foxinmy.weixin4j.msg.model.Music;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 客服音乐消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">客服音乐消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">客服音乐消息</a>
* @see com.foxinmy.weixin4j.msg.model.Music
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify#toJson()
*/
@ -24,44 +27,20 @@ public class MusicNotify extends BaseNotify {
super(touser, MessageType.music);
}
public void pushMusic(String title, String desc, String url, String hqUrl, String mediaId) {
this.music = new $();
this.music.thumbMediaId = mediaId;
this.music.desc = desc;
this.music.hqMusicUrl = hqUrl;
this.music.musicUrl = url;
this.music.title = title;
public void pushMusic(String musicurl, String hqUrl, String mediaId) {
this.music = new Music(null, null, musicurl, hqUrl, mediaId);
}
@XStreamAlias("music")
private $ music;
private static class $ {
private String title;
@XStreamAlias("description")
private String desc;
@XStreamAlias("musicurl")
private String musicUrl;
@XStreamAlias("hqmusicurl")
private String hqMusicUrl;
@XStreamAlias("thumb_media_id")
private String thumbMediaId;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(music ,title=").append(title);
sb.append(" ,description=").append(desc);
sb.append(" ,musicURL=").append(musicUrl);
sb.append(" ,hqMusicUrl=").append(hqMusicUrl);
sb.append(" ,thumbMediaId=").append(thumbMediaId).append(")");
return sb.toString();
}
private Music music;
public void setMusic(Music music) {
this.music = music;
}
@Override
public String toString() {
return String.format("[VideoNotify touser=%s ,msgtype=%s ,music=%s]", super.getTouser(), super.getMsgtype().name(), this.music.toString());
return String.format("[MusicNotify touser=%s ,msgtype=%s ,music=%s]",
super.getTouser(), super.getMsgtype().name(),
this.music.toString());
}
}

View File

@ -1,14 +1,17 @@
package com.foxinmy.weixin4j.msg.notify;
import com.foxinmy.weixin4j.msg.model.Text;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 客服文本消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">客服文本消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E6.96.87.E6.9C.AC.E6.B6.88.E6.81.AF">客服文本消息</a>
* @see com.foxinmy.weixin.msg.model.Text
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify#toJson()
*/
@ -22,27 +25,24 @@ public class TextNotify extends BaseNotify {
public TextNotify(String content) {
super(MessageType.text);
this.text = new $(content);
this.text = new Text(content);
}
public TextNotify(String content, String touser) {
super(touser, MessageType.text);
this.text = new $(content);
this.text = new Text(content);
}
@XStreamAlias("text")
private $ text;
private static class $ {
@XStreamAlias("content")
private String content;
public $(String content) {
this.content = content;
}
public void setContent(String content) {
this.text = new Text(content);
}
private Text text;
@Override
public String toString() {
return String.format("[TextNotify touser=%s ,msgtype=%s ,content=%s]", super.getTouser(), super.getMsgtype().name(), this.text.content);
return String.format("[TextNotify touser=%s ,msgtype=%s ,content=%s]",
super.getTouser(), super.getMsgtype().name(),
this.text.getContent());
}
}

View File

@ -1,14 +1,17 @@
package com.foxinmy.weixin4j.msg.notify;
import com.foxinmy.weixin4j.msg.model.Video;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 客服视频消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">客服视频消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">客服视频消息</a>
* @see com.foxinmy.weixin4j.msg.model.Video
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify#toJson()
*/
@ -24,35 +27,20 @@ public class VideoNotify extends BaseNotify {
super(touser, MessageType.video);
}
public void pushVideo(String mediaId, String title, String desc) {
this.video = new $(mediaId, title, desc);
public void pushVideo(String mediaId, String thumbMediaId) {
this.video = new Video(mediaId, thumbMediaId);
}
@XStreamAlias("video")
private $ video;
private Video video;
private static class $ {
@XStreamAlias("media_id")
private String mediaId;
private String title;
@XStreamAlias("description")
private String desc;
public $(String mediaId, String title, String desc) {
this.mediaId = mediaId;
this.title = title;
this.desc = desc;
public void setVideo(Video video) {
this.video = video;
}
@Override
public String toString() {
return String.format("(video mediaId=%s ,title=%s ,description=%s)", mediaId, title, desc);
}
}
@Override
public String toString() {
return String.format("[VideoNotify touser=%s ,msgtype=%s ,video=%s]", super.getTouser(), super.getMsgtype().name(), this.video.toString());
return String.format("[VideoNotify touser=%s ,msgtype=%s ,video=%s]",
super.getTouser(), super.getMsgtype().name(),
this.video.toString());
}
}

View File

@ -1,14 +1,17 @@
package com.foxinmy.weixin4j.msg.notify;
import com.foxinmy.weixin4j.msg.model.Voice;
import com.foxinmy.weixin4j.type.MessageType;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 客服语音消息
*
* @author jy.hu
* @date 2014年4月4日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">客服语音消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E5%AE%A2%E6%9C%8D%E6%B6%88%E6%81%AF#.E5.8F.91.E9.80.81.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">客服语音消息</a>
* @see com.foxinmy.weixin4j.msg.model.Voice
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify
* @see com.foxinmy.weixin4j.msg.notify.BaseNotify#toJson()
*/
@ -20,30 +23,25 @@ public class VoiceNotify extends BaseNotify {
super(MessageType.voice);
}
public VoiceNotify(String mediaId) {
super(MessageType.voice);
this.voice = new $(mediaId);
public VoiceNotify(String touser) {
super(touser, MessageType.voice);
}
public VoiceNotify(String mediaId, String touser) {
super(touser, MessageType.voice);
this.voice = new $(mediaId);
this.pushMediaId(mediaId);
}
@XStreamAlias("voice")
private $ voice;
private static class $ {
@XStreamAlias("media_id")
private String mediaId;
public $(String mediaId) {
this.mediaId = mediaId;
}
public void pushMediaId(String mediaId) {
this.voice = new Voice(mediaId);
}
private Voice voice;
@Override
public String toString() {
return String.format("[VoiceNotify touser=%s ,msgtype=%s ,mediaId=%s]", super.getTouser(), super.getMsgtype().name(), this.voice.mediaId);
return String.format("[VoiceNotify touser=%s ,msgtype=%s ,mediaId=%s]",
super.getTouser(), super.getMsgtype().name(),
this.voice.getMediaId());
}
}

View File

@ -4,16 +4,21 @@ import java.util.LinkedList;
import java.util.List;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.msg.model.Article;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复图文消息
*
* @className ArticleMessage
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF">回复图文消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E5.9B.BE.E6.96.87.E6.B6.88.E6.81.AF">回复图文消息</a>
* @see com.foxinmy.weixin.msg.model.Article
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
*/
@ -21,19 +26,14 @@ public class ArticleMessage extends BaseMessage {
private static final int MAX_ARTICLE_COUNT = 10;
private static final long serialVersionUID = -7331603018352309317L;
public ArticleMessage() {
super(MessageType.news);
}
public ArticleMessage(String toUserName) {
super(MessageType.news);
super.setToUserName(toUserName);
public ArticleMessage(BaseMessage inMessage) {
super(MessageType.news, inMessage);
}
@XStreamAlias("ArticleCount")
private int count; // 图文消息个数限制为10条以内
@XStreamAlias("Articles")
private List<Article> articles;
private LinkedList<Article> articles;
public List<Article> getArticles() {
return this.articles;
@ -44,39 +44,55 @@ public class ArticleMessage extends BaseMessage {
return;
}
if (this.articles == null) {
this.articles = new LinkedList<ArticleMessage.Article>();
this.articles = new LinkedList<Article>();
}
this.articles.add(new Article(title, desc, picUrl, url));
count++;
}
@XStreamAlias("item")
private static class Article {
@XStreamAlias("Title")
private String title; // 图文消息标题
@XStreamAlias("Description")
private String desc; // 图文消息描述
@XStreamAlias("PicUrl")
private String picUrl; // 图片链接支持JPGPNG格式较好的效果为大图360*200小图200*200
@XStreamAlias("Url")
private String url; // 点击图文消息跳转链接
public void pushFirstArticle(String title, String desc, String picUrl,
String url) {
if (this.articles == null) {
this.articles = new LinkedList<Article>();
}
this.articles.addFirst(new Article(title, desc, picUrl, url));
}
public Article(String title, String desc, String picUrl, String url) {
this.title = title;
this.desc = desc;
this.picUrl = picUrl;
this.url = url;
public void pushLastArticle(String title, String desc, String picUrl,
String url) {
if (this.articles == null) {
this.articles = new LinkedList<Article>();
}
this.articles.addLast(new Article(title, desc, picUrl, url));
}
public Article removeLastArticle() {
if (this.articles != null) {
return this.articles.removeLast();
}
return null;
}
public Article removeFirstArticle() {
if (this.articles != null) {
return this.articles.removeFirst();
}
return null;
}
public boolean isMaxCount() {
return this.articles.size() == MAX_ARTICLE_COUNT;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(Article ,title=").append(title);
sb.append(" ,description=").append(desc);
sb.append(" ,picUrl=").append(picUrl);
sb.append(" ,url=").append(url).append(")");
return sb.toString();
}
public String toXml() {
XStream xstream = getXStream();
xstream.alias("item", Article.class);
xstream.aliasField("Title", Article.class, "title");
xstream.aliasField("Description", Article.class, "desc");
xstream.aliasField("PicUrl", Article.class, "picUrl");
xstream.aliasField("Url", Article.class, "url");
return xstream.toXML(this);
}
@Override

View File

@ -1,38 +1,50 @@
package com.foxinmy.weixin4j.msg.out;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.msg.model.Image;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复图片消息
*
* @className ImageMessage
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">回复图片消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E5.9B.BE.E7.89.87.E6.B6.88.E6.81.AF">回复图片消息</a>
* @see com.foxinmy.weixin4j.msg.model.Image
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
*/
public class ImageMessage extends BaseMessage {
private static final long serialVersionUID = 6998255203997554731L;
public ImageMessage() {
super(MessageType.image);
public ImageMessage(BaseMessage inMessage) {
super(MessageType.image, inMessage);
super.getMsgType().setMessageClass(ImageMessage.class);
}
public ImageMessage(String mediaId, BaseMessage inMessage) {
super(MessageType.image, inMessage);
super.getMsgType().setMessageClass(ImageMessage.class);
this.pushMediaId(mediaId);
}
@XStreamAlias("Image")
private Image image;
public void pushMediaId(String mediaId) {
this.image = new Image();
this.image.mediaId = mediaId;
this.image = new Image(mediaId);
}
private static class Image {
@XStreamAlias("MediaId")
private String mediaId;
@Override
public String toXml() {
XStream xstream = getXStream();
xstream.aliasField("MediaId", Image.class, "mediaId");
return xstream.toXML(this);
}
@Override
@ -41,7 +53,7 @@ public class ImageMessage extends BaseMessage {
sb.append("[ImageMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,mediaId=").append(this.image.mediaId);
sb.append(" ,mediaId=").append(this.image.getMediaId());
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();

View File

@ -1,16 +1,21 @@
package com.foxinmy.weixin4j.msg.out;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.msg.model.Music;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复音乐消息
*
* @className MusicMessage
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">回复音乐消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E9.9F.B3.E4.B9.90.E6.B6.88.E6.81.AF">回复音乐消息</a>
* @see com.foxinmy.weixin4j.msg.model.Music
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
*/
@ -18,48 +23,30 @@ public class MusicMessage extends BaseMessage {
private static final long serialVersionUID = 4384403772658796395L;
public MusicMessage() {
super(MessageType.music);
public MusicMessage(BaseMessage inMessage) {
super(MessageType.music, inMessage);
}
@XStreamAlias("Music")
private Music music;
public Music getMusic() {
return this.music;
public void pushMusic(String mediaId) {
this.music = new Music(mediaId);
}
public void pushMusic(String title, String desc, String url, String hqUrl, String mediaId) {
this.music = new Music();
this.music.thumbMediaId = mediaId;
this.music.desc = desc;
this.music.hqMusicUrl = hqUrl;
this.music.MusicURL = url;
this.music.title = title;
public void setMusic(Music music) {
this.music = music;
}
private static class Music {
@XStreamAlias("Title")
private String title; // 音乐标题
@XStreamAlias("Description")
private String desc; // 音乐描述
@XStreamAlias("MusicURL")
private String MusicURL; // 音乐链接
@XStreamAlias("HQMusicUrl")
private String hqMusicUrl; // 高质量音乐链接WIFI环境优先使用该链接播放音乐
@XStreamAlias("ThumbMediaId")
private String thumbMediaId; // 缩略图的媒体id通过上传多媒体文件得到的id
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(Music ,title=").append(title);
sb.append(" ,description=").append(desc);
sb.append(" ,musicURL=").append(MusicURL);
sb.append(" ,hqMusicUrl=").append(hqMusicUrl);
sb.append(" ,thumbMediaId=").append(thumbMediaId).append(")");
return sb.toString();
}
public String toXml() {
XStream xstream = getXStream();
xstream.aliasField("MediaId", Music.class, "musicUrl");
xstream.aliasField("Title", Music.class, "title");
xstream.aliasField("Description", Music.class, "desc");
xstream.aliasField("HQMusicUrl", Music.class, "hqMusicUrl");
xstream.aliasField("ThumbMediaId", Music.class, "thumbMediaId");
return xstream.toXML(this);
}
@Override
@ -68,7 +55,7 @@ public class MusicMessage extends BaseMessage {
sb.append("[MusicMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,music=").append(getMusic().toString());
sb.append(" ,music=").append(music.toString());
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();

View File

@ -0,0 +1,117 @@
package com.foxinmy.weixin4j.msg.out;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import com.alibaba.fastjson.JSON;
/**
* 模板消息
*
* @className TemplateMessage
* @author jy
* @date 2014年9月29日
* @since JDK 1.7
* @see
*/
public class TemplateMessage implements Serializable {
private static final long serialVersionUID = 7950608393821661436L;
private String touser;
private String template_id;
private String url;
private String topcolor = "#FF0000";
private Map<String, Item> data;
public void pushData(String key, String value) {
this.data.put(key, new Item(value));
}
public TemplateMessage(String touser, String template_id, String url) {
this.touser = touser;
this.template_id = template_id;
this.url = url;
this.data = new HashMap<String, Item>();
}
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() + "]";
}
}
public String getTouser() {
return touser;
}
public void setTouser(String touser) {
this.touser = touser;
}
public String getTemplate_id() {
return template_id;
}
public void setTemplate_id(String template_id) {
this.template_id = template_id;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getTopcolor() {
return topcolor;
}
public void setTopcolor(String topcolor) {
this.topcolor = topcolor;
}
public Map<String, Item> getData() {
return data;
}
public void setData(Map<String, Item> data) {
this.data = data;
}
@Override
public String toString() {
return "TemplateMessage [touser=" + touser + ", template_id="
+ template_id + ", url=" + url + ", topcolor=" + topcolor
+ ", data=" + data + "]";
}
public String toJson() {
return JSON.toJSONString(this);
}
}

View File

@ -0,0 +1,25 @@
package com.foxinmy.weixin4j.msg.out;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.type.MessageType;
/**
* 转移消息到多客服端消息
*
* @className TransferMessage
* @author jy.hu
* @date 2014年6月28日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%B0%86%E6%B6%88%E6%81%AF%E8%BD%AC%E5%8F%91%E5%88%B0%E5%A4%9A%E5%AE%A2%E6%9C%8D">多客服转移消息</a>
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
*/
public class TransferMessage extends BaseMessage {
private static final long serialVersionUID = -5479496746108594940L;
public TransferMessage(BaseMessage inMessage) {
super(MessageType.transfer_customer_service,inMessage);
}
}

View File

@ -1,16 +1,21 @@
package com.foxinmy.weixin4j.msg.out;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.msg.model.Video;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 回复视频消息
*
* @className VideoMessage
* @author jy.hu
* @date 2014年4月6日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">回复视频消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E8.A7.86.E9.A2.91.E6.B6.88.E6.81.AF">回复视频消息</a>
* @see com.foxinmy.weixin4j.msg.model.Video
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
*/
@ -18,41 +23,30 @@ public class VideoMessage extends BaseMessage {
private static final long serialVersionUID = -1013075358679078381L;
public VideoMessage() {
super(MessageType.video);
public VideoMessage(BaseMessage inMessage) {
super(MessageType.video, inMessage);
super.getMsgType().setMessageClass(VideoMessage.class);
}
@XStreamAlias("Video")
private Video video;
public Video getVideo() {
return this.video;
public void pushVideo(String mediaId) {
this.video = new Video(mediaId);
}
public void pushVideo(String mediaId, String title, String desc) {
this.video = new Video();
this.video.desc = desc;
this.video.mediaId = mediaId;
this.video.title = title;
public void setVideo(Video video) {
this.video = video;
}
private static class Video {
@XStreamAlias("MediaId")
private String mediaId;
@XStreamAlias("Title")
private String title;
@XStreamAlias("Description")
private String desc;
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("(Video mediaId=").append(mediaId);
sb.append(" ,title=").append(title);
sb.append(" ,desc=").append(desc).append(")");
return super.toString();
}
public String toXml() {
XStream xstream = getXStream();
xstream.aliasField("MediaId", Video.class, "mediaId");
xstream.aliasField("Title", Video.class, "title");
xstream.aliasField("Description", Video.class, "desc");
xstream.omitField(Video.class, "thumbMediaId");
return xstream.toXML(this);
}
@Override
@ -61,7 +55,7 @@ public class VideoMessage extends BaseMessage {
sb.append("[VideoMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,video=").append(getVideo().toString());
sb.append(" ,video=").append(video.toString());
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();

View File

@ -1,16 +1,21 @@
package com.foxinmy.weixin4j.msg.out;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.msg.model.Voice;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.xml.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
/**
* 语音消息
*
* @className VoiceMessage
* @author jy.hu
* @date 2014年3月23日
* @since JDK 1.7
* @see <a href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">回复语音消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E5%8F%91%E9%80%81%E8%A2%AB%E5%8A%A8%E5%93%8D%E5%BA%94%E6%B6%88%E6%81%AF#.E5.9B.9E.E5.A4.8D.E8.AF.AD.E9.9F.B3.E6.B6.88.E6.81.AF">回复语音消息</a>
* @see com.foxinmy.weixin4j.msg.model.Voice
* @see com.foxinmy.weixin4j.msg.BaseMessage
* @see com.foxinmy.weixin4j.msg.BaseMessage#toXml()
*/
@ -18,36 +23,38 @@ public class VoiceMessage extends BaseMessage {
private static final long serialVersionUID = -7944926238652243793L;
public VoiceMessage() {
super(MessageType.voice);
public VoiceMessage(BaseMessage inMessage) {
super(MessageType.voice, inMessage);
super.getMsgType().setMessageClass(VoiceMessage.class);
}
public VoiceMessage(String mediaId, BaseMessage inMessage) {
super(MessageType.voice, inMessage);
super.getMsgType().setMessageClass(VoiceMessage.class);
this.pushMediaId(mediaId);
}
@XStreamAlias("Voice")
private Voice voice;
public Voice getVocie() {
return voice;
}
public void pushMediaId(String mediaId) {
this.voice = new Voice();
this.voice.setMediaId(mediaId);
this.voice = new Voice(mediaId);
}
private static class Voice {
@XStreamAlias("MediaId")
private String mediaId;
@Override
public String toXml() {
XStream xstream = getXStream();
xstream.aliasField("MediaId", Voice.class, "mediaId");
return xstream.toXML(this);
}
private void setMediaId(String mediaId) {
this.mediaId = mediaId;
}
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("[VoiceMessage ,toUserName=").append(super.getToUserName());
sb.append(" ,fromUserName=").append(super.getFromUserName());
sb.append(" ,msgType=").append(super.getMsgType().name());
sb.append(" ,mediaId=").append(getVocie().mediaId);
sb.append(" ,mediaId=").append(voice.getMediaId());
sb.append(" ,createTime=").append(super.getCreateTime());
sb.append(" ,msgId=").append(super.getMsgId()).append("]");
return sb.toString();

View File

@ -0,0 +1,55 @@
package com.foxinmy.weixin4j.type;
/**
* 自定义菜单类型 <br/>
* <font color="red">scancode_push location_selec
* 仅支持微信iPhone5.4.1以上版本和Android5 .4以上版本的微信用户 旧版本微信用户点击后将没有回应
* 开发者也不能正常接收到事件推送</font>
*
* @className ButtonType
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E8%87%AA%E5%AE%9A%E4%B9%89%E8%8F%9C%E5%8D%95%E5%88%9B%E5%BB%BA%E6%8E%A5%E5%8F%A3">按钮类型</a>
*/
public enum ButtonType {
/**
* 点击推事件 用户点击click类型按钮后微信服务器会通过消息接口推送消息类型为event
* 的结构给开发者参考消息接口指南并且带上按钮中开发者填写的key值开发者可以通过自定义的key值与用户进行交互
*/
click,
/**
* 跳转URL 用户点击view类型按钮后微信客户端将会打开开发者在按钮中填写的网页URL可与网页授权获取用户基本信息接口结合获得用户基本信息
*/
view,
/**
* 扫码推事件 用户点击按钮后微信客户端将调起扫一扫工具完成扫码操作后显示扫描结果如果是URL将进入URL且会将扫码的结果传给开发者
* 开发者可以下发消息
*/
scancode_push,
/**
* 扫码推事件且弹出消息接收中提示框用户点击按钮后微信客户端将调起扫一扫工具完成扫码操作后将扫码的结果传给开发者同时收起扫一扫工具
* 然后弹出消息接收中提示框随后可能会收到开发者下发的消息
*/
scancode_waitmsg,
/**
* 弹出系统拍照发图用户点击按钮后微信客户端将调起系统相机完成拍照操作后会将拍摄的相片发送给开发者并推送事件给开发者同时收起系统相机
* 随后可能会收到开发者下发的消息
*/
pic_sysphoto,
/**
* 弹出拍照或者相册发图用户点击按钮后微信客户端将弹出选择器供用户选择拍照或者从手机相册选择用户选择后即走其他两种流程
*/
pic_photo_or_albu,
/**
* 弹出微信相册发图器用户点击按钮后微信客户端将调起微信相册完成选择操作后将选择的相片发送给开发者的服务器并推送事件给开发者同时收起相册
* 随后可能会收到开发者下发的消息
*/
pic_weixin,
/**
* 弹出地理位置选择器用户点击按钮后微信客户端将调起地理位置选择工具完成选择操作后将选择的地理位置发送给开发者的服务器同时收起位置选择工具
* 随后可能会收到开发者下发的消息
*/
location_select;
}

View File

@ -3,20 +3,35 @@ package com.foxinmy.weixin4j.type;
import com.foxinmy.weixin4j.msg.event.EventMessage;
import com.foxinmy.weixin4j.msg.event.LocationEventMessage;
import com.foxinmy.weixin4j.msg.event.MassEventMessage;
import com.foxinmy.weixin4j.msg.event.MenuEventMessage;
import com.foxinmy.weixin4j.msg.event.ScanEventMessage;
import com.foxinmy.weixin4j.msg.event.ScribeEventMessage;
import com.foxinmy.weixin4j.msg.event.TemplatesendjobfinishMessage;
import com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage;
import com.foxinmy.weixin4j.msg.event.menu.MenuLocationEventMessage;
import com.foxinmy.weixin4j.msg.event.menu.MenuPhotoEventMessage;
import com.foxinmy.weixin4j.msg.event.menu.MenuScanEventMessage;
/**
*
* 事件类型
* @author jy.hu
*
* @className EventType
* @author jy
* @date 2014年9月30日
* @since JDK 1.7
* @see
*/
public enum EventType {
subscribe(ScribeEventMessage.class), unsubscribe(ScribeEventMessage.class),
scan(ScanEventMessage.class),click(MenuEventMessage.class),view(MenuEventMessage.class),
location(LocationEventMessage.class),MASSSENDJOBFINISH(MassEventMessage.class);
subscribe(ScribeEventMessage.class), unsubscribe(ScribeEventMessage.class), scan(
ScanEventMessage.class), scancode_push(MenuScanEventMessage.class), view(
MenuEventMessage.class), scancode_waitmsg(
MenuScanEventMessage.class), pic_sysphoto(
MenuPhotoEventMessage.class), pic_photo_or_album(
MenuPhotoEventMessage.class), pic_weixin(
MenuPhotoEventMessage.class), location_select(
MenuLocationEventMessage.class), click(MenuEventMessage.class), location(
LocationEventMessage.class), massendjobfinish(
MassEventMessage.class), templatesendjobfinish(
TemplatesendjobfinishMessage.class);
private Class<? extends EventMessage> eventClass;

View File

@ -6,13 +6,20 @@ package com.foxinmy.weixin4j.type;
* 语音(voice):256K,播放长度不超过60s,支持AMR\MP3格式<br/>
* 视频(video):1MB,支持MP4格式<br/>
* 缩略图(thumb):64KB,支持JPG格式<br/>
* <p><font color='red'>媒体文件在后台保存时间为3天,即3天后media_id失效</font><p/>
* <p>
* <font color='red'>媒体文件在后台保存时间为3天,即3天后media_id失效</font>
* <p/>
*
* @author jy.hu
* @date 2014年4月2日
* @since JDK 1.7
*/
public enum MediaType {
image("image/jpeg",".jpg"), voice("binary/octet-stream","amr"), vedio("binary/octet-stream","mp4"), thumb("image/jpeg","jpg");
image("image/jpeg", "jpg"), voice("binary/octet-stream", "amr"), vedio(
"binary/octet-stream", "mp4"), thumb("image/jpeg", "jpg"), text(
"application/json", ""), music("binary/octet-stream", "mp3"), news(
"application/json", ""), mpnews("application/json", ""), mpvideo(
"binary/octet-stream", "");
MediaType(String contentType, String formatType) {
this.contentType = contentType;
@ -26,6 +33,7 @@ public enum MediaType {
}
private String formatType;
public String getFormatType() {
return formatType;
}

View File

@ -10,6 +10,7 @@ import com.foxinmy.weixin4j.msg.in.VideoMessage;
import com.foxinmy.weixin4j.msg.in.VoiceMessage;
import com.foxinmy.weixin4j.msg.out.ArticleMessage;
import com.foxinmy.weixin4j.msg.out.MusicMessage;
import com.foxinmy.weixin4j.msg.out.TransferMessage;
/**
*
@ -20,9 +21,13 @@ import com.foxinmy.weixin4j.msg.out.MusicMessage;
*/
public enum MessageType {
// 接收到的消息类型
text(TextMessage.class), image(ImageMessage.class), voice(VoiceMessage.class), video(VideoMessage.class), location(LocationMessage.class), link(LinkMessage.class), event(EventMessage.class),
text(TextMessage.class), image(ImageMessage.class), voice(
VoiceMessage.class), video(VideoMessage.class), location(
LocationMessage.class), link(LinkMessage.class), event(
EventMessage.class),
// 发送的消息类型
music(MusicMessage.class), news(ArticleMessage.class);
music(MusicMessage.class), news(ArticleMessage.class), transfer_customer_service(
TransferMessage.class);
private Class<? extends BaseMessage> messageClass;
MessageType(Class<? extends BaseMessage> messageClass) {

View File

@ -8,8 +8,8 @@ import java.util.regex.Pattern;
import com.foxinmy.weixin4j.WeixinProxy;
public class WeixinConfig {
public WeixinConfig() {
public class ConfigUtil {
public ConfigUtil() {
}
private static Properties props = new Properties();
@ -38,7 +38,6 @@ public class WeixinConfig {
m.appendTail(sb);
return sb.toString();
}
public static void main(String[] args) {
System.out.println(getValue("api_token_uri"));
}

View File

@ -0,0 +1,67 @@
package com.foxinmy.weixin4j.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.nio.charset.Charset;
/**
* IOUtil
*
* @className IOUtil
* @author jy.hu
* @date 2014年9月22日
* @since JDK 1.7
* @see org.apache.commons.io.IOUtils
*/
public class IOUtil {
private static final int EOF = -1;
private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
public static byte[] toByteArray(Reader input) throws IOException {
return toByteArray(input, Charset.defaultCharset());
}
public static byte[] toByteArray(Reader input, Charset encoding) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
copy(input, output, encoding);
return output.toByteArray();
}
public static void copy(Reader input, OutputStream output, Charset encoding) throws IOException {
OutputStreamWriter out = new OutputStreamWriter(output, encoding);
copyLarge(input, out, new char[DEFAULT_BUFFER_SIZE]);
out.flush();
}
public static byte[] toByteArray(InputStream input) throws IOException {
ByteArrayOutputStream output = new ByteArrayOutputStream();
copyLarge(input, output, new byte[DEFAULT_BUFFER_SIZE]);
return output.toByteArray();
}
private static long copyLarge(InputStream input, OutputStream output, byte[] buffer) throws IOException {
long count = 0;
int n = 0;
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
private static long copyLarge(Reader input, Writer output, char[] buffer) throws IOException {
long count = 0;
int n = 0;
while (EOF != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}
}

View File

@ -0,0 +1,135 @@
package com.foxinmy.weixin4j.util;
import java.io.InputStream;
import java.util.Arrays;
import org.apache.commons.codec.digest.DigestUtils;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.DocumentHelper;
import org.dom4j.io.SAXReader;
import org.jsoup.helper.StringUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.type.EventType;
import com.foxinmy.weixin4j.type.MessageType;
import com.foxinmy.weixin4j.xml.XStream;
public class MessageUtil {
private final static Logger log = LoggerFactory.getLogger(MessageUtil.class);
/**
* 验证微信签名
*
* @param echostr
* 随机字符串
* @param timestamp
* 时间戳
* @param nonce
* 随机数
* @param signature
* 微信加密签名signature结合了开发者填写的token参数和请求中的timestamp参数nonce参数
* @return 开发者通过检验signature对请求进行相关校验若确认此次GET请求来自微信服务器
* 请原样返回echostr参数内容则接入生效 成为开发者成功否则接入失败
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E5%85%A5%E6%8C%87%E5%8D%97">接入指南</a>
*/
public static String signature(String echostr, String timestamp, String nonce, String signature) {
String app_token = ConfigUtil.getValue("app_token");
if (StringUtil.isBlank(app_token)) {
log.error("signature fail : token is null!");
return null;
}
if (StringUtil.isBlank(echostr) || StringUtil.isBlank(timestamp) || StringUtil.isBlank(nonce)) {
log.error("signature fail : invalid parameter!");
return null;
}
String _signature = null;
try {
String[] a = { app_token, timestamp, nonce };
Arrays.sort(a);
StringBuilder sb = new StringBuilder(3);
for (String str : a) {
sb.append(str);
}
_signature = DigestUtils.sha1Hex(sb.toString());
} catch (Exception e) {
log.error("signature error", e);
}
if (signature.equals(_signature)) {
return echostr;
} else {
log.error("signature fail : invalid signature!");
return null;
}
}
/**
* xml消息转换为消息对象
* <p>
* 微信服务器在五秒内收不到响应会断掉连接,并且重新发起请求,总共重试三次
* </p>
*
* @param xml
* 消息字符串
* @return 消息对象
* @throws DocumentException
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E9%AA%8C%E8%AF%81%E6%B6%88%E6%81%AF%E7%9C%9F%E5%AE%9E%E6%80%A7">验证消息的合法性</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E6%99%AE%E9%80%9A%E6%B6%88%E6%81%AF">普通消息</a>
* @see <a
* href="http://mp.weixin.qq.com/wiki/index.php?title=%E6%8E%A5%E6%94%B6%E4%BA%8B%E4%BB%B6%E6%8E%A8%E9%80%81">事件触发</a>
* @see com.foxinmy.weixin4j.type.MessageType
* @see com.feican.weixin.msg.BaeMessage
* @see com.foxinmy.weixin4j.msg.TextMessage
* @see com.foxinmy.weixin4j.msg.in.ImageMessage
* @see com.foxinmy.weixin4j.msg.in.VoiceMessage
* @see com.foxinmy.weixin4j.msg.in.VideoMessage
* @see com.foxinmy.weixin4j.msg.in.LocationMessage
* @see com.foxinmy.weixin4j.msg.in.LinkMessage
* @see com.foxinmy.weixin4j.msg.event.ScribeEventMessage
* @see com.foxinmy.weixin4j.msg.event.ScanEventMessage
* @see com.foxinmy.weixin4j.msg.event.LocationEventMessage
* @see com.foxinmy.weixin4j.msg.event.menu.MenuEventMessage
*/
public static BaseMessage xml2msg(String xml) throws DocumentException {
if (StringUtil.isBlank(xml))
return null;
Document doc = DocumentHelper.parseText(xml);
String type = doc.selectSingleNode("/xml/MsgType").getStringValue();
if (StringUtil.isBlank(type)) {
return null;
}
XStream xstream = new XStream();
MessageType messageType = MessageType.valueOf(type.toLowerCase());
Class<? extends BaseMessage> messageClass = messageType.getMessageClass();
if (messageType == MessageType.event) {
type = doc.selectSingleNode("/xml/Event").getStringValue();
messageClass = EventType.valueOf(type.toLowerCase()).getEventClass();
}
xstream.alias("xml", messageClass);
xstream.ignoreUnknownElements();
xstream.autodetectAnnotations(true);
xstream.processAnnotations(messageClass);
return xstream.fromXML(doc.asXML(), messageClass);
}
/**
* xml消息转换为消息对象
*
* @param inputStream
* 带消息字符串的输入流
* @return 消息对象
* @throws DocumentException
* @see {@link com.foxinmy.weixin4j.WeixinProxy#xml2msg(String)}
*/
public static BaseMessage xml2msg(InputStream inputStream) throws DocumentException {
SAXReader reader = new SAXReader();
Document doc = reader.read(inputStream);
return xml2msg(doc.asXML());
}
}

View File

@ -1,8 +0,0 @@
package com.foxinmy.weixin4j.util;
public class WeixinUtil {
public static boolean isBlank(String str) {
return str == null || str.isEmpty();
}
}

View File

@ -9,7 +9,7 @@ import org.junit.Test;
import com.foxinmy.weixin4j.WeixinProxy;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Button;
import com.foxinmy.weixin4j.model.Button.BtnType;
import com.foxinmy.weixin4j.type.ButtonType;
/**
* 自定义菜单测试
@ -31,7 +31,7 @@ public class ButtonTest {
List<Button> btnList = new ArrayList<Button>();
Button b = new Button("test");
b.setType(BtnType.click);
b.setType(ButtonType.click);
b.setKey("123");
btnList.add(b);

View File

@ -50,7 +50,7 @@ public class GroupTest {
@Test
public void getid() {
try {
System.out.println(weixinProxy.findGroupByOpenId("owGBft_vbBbOaQOmpEUE4xDLeRSU"));
System.out.println(weixinProxy.getGroupByOpenId("owGBft_vbBbOaQOmpEUE4xDLeRSU"));
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());

View File

@ -0,0 +1,22 @@
package com.foxinmy.weixin4j.test;
import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.HttpRequest;
public class HttpTest {
private static HttpRequest request;
static {
request = new HttpRequest();
}
@Test
public void test(){
try {
System.out.println(request.get("http://www.baidu.com"));
} catch (WeixinException e) {
e.printStackTrace();
}
}
}

View File

@ -31,7 +31,7 @@ public class MediaTest {
File file = new File("D:\\test.jpg");
try {
System.out.println(weixinProxy.uploadMedia(file, MediaType.image));
//usAxLEJxFXAjXVlLu_BSw0GvS2YEEoGeelRBybNZBGvMsdxiIcD1F9yBWYd9jVZx
//vvU_AUtovWyfAxQ8J1DsCoNMtK6U_bUmTpe6lpINUOVRLvt_7rtO4zxzBpPgkmay
} catch (WeixinException e) {
System.out.println(e.getErrorMsg());
}
@ -40,7 +40,7 @@ public class MediaTest {
@Test
public void download() {
try {
System.out.println(weixinProxy.downloadMedia("usAxLEJxFXAjXVlLu_BSw0GvS2YEEoGeelRBybNZBGvMsdxiIcD1F9yBWYd9jVZx", MediaType.image));
System.out.println(weixinProxy.downloadMedia("vvU_AUtovWyfAxQ8J1DsCoNMtK6U_bUmTpe6lpINUOVRLvt_7rtO4zxzBpPgkmay", MediaType.image));
} catch (WeixinException e) {
System.out.println(e.getErrorMsg());
}

View File

@ -0,0 +1,194 @@
package com.foxinmy.weixin4j.test;
import org.junit.Test;
import com.foxinmy.weixin4j.util.MessageUtil;
/**
* 接收事件消息格式测试
*
* @author jy.hu
* @date 2014年3月24日
* @since JDK 1.7
*/
public class MessageEventInTest {
private StringBuilder xmlSb = new StringBuilder();
/***************** event message *********************/
@Test
public void scribe() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[subscribe]]></Event>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void scan() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[SCAN]]></Event>");
xmlSb.append("<EventKey><![CDATA[SCENE_VALUE]]></EventKey>");
xmlSb.append("<Ticket><![CDATA[TICKET]]></Ticket>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void scan_scribe() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml><ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[subscribe]]></Event>");
xmlSb.append("<EventKey><![CDATA[qrscene_123123]]></EventKey>");
xmlSb.append("<Ticket><![CDATA[TICKET]]></Ticket>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void location1() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[fromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[LOCATION]]></Event>");
xmlSb.append("<Latitude>23.137466</Latitude>");
xmlSb.append("<Longitude>113.352425</Longitude>");
xmlSb.append("<Precision>119.385040</Precision>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void menu_click() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[CLICK]]></Event>");
xmlSb.append("<EventKey><![CDATA[EVENTKEY]]></EventKey>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void menu_link() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[VIEW]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void menu_scan() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[scancode_waitmsg]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<ScanCodeInfo><ScanType><![CDATA[qrcode]]></ScanType>");
xmlSb.append("<ScanResult><![CDATA[1]]></ScanResult>");
xmlSb.append("</ScanCodeInfo>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void menu_photo() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[pic_weixin]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<SendPicsInfo><Count>1</Count>");
xmlSb.append("<PicList><item><PicMd5Sum><![CDATA[1b5f7c23b5bf75682a53e7b6d163e185]]></PicMd5Sum>");
xmlSb.append("</item></PicList></SendPicsInfo>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void menu_location() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[location_select]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("<SendLocationInfo><Location_X><![CDATA[23]]></Location_X>");
xmlSb.append("<Location_Y><![CDATA[113]]></Location_Y>");
xmlSb.append("<Scale><![CDATA[15]]></Scale>");
xmlSb.append("<Label><![CDATA[ 广州市海珠区客村艺苑路 106号]]></Label>");
xmlSb.append("<Poiname><![CDATA[]]></Poiname></SendLocationInfo>");
xmlSb.append("</xml>");
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
}

View File

@ -1,134 +1,19 @@
package com.foxinmy.weixin4j.test;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.WeixinProxy;
import com.foxinmy.weixin4j.util.MessageUtil;
/**
* 接收消息格式测试
* 接受一般消息格式测试
*
* @author jy.hu
* @date 2014年3月24日
* @since JDK 1.7
*/
public class MessageInTest {
private StringBuilder xmlSb = new StringBuilder();
private WeixinProxy weixinProxy;
@Before
public void init(){
weixinProxy = new WeixinProxy();
}
/***************** event message *********************/
@Test
public void scribe() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[subscribe]]></Event>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void scan() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[SCAN]]></Event>");
xmlSb.append("<EventKey><![CDATA[SCENE_VALUE]]></EventKey>");
xmlSb.append("<Ticket><![CDATA[TICKET]]></Ticket>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void scan_scribe() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml><ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[subscribe]]></Event>");
xmlSb.append("<EventKey><![CDATA[qrscene_123123]]></EventKey>");
xmlSb.append("<Ticket><![CDATA[TICKET]]></Ticket>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void location1() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[fromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[LOCATION]]></Event>");
xmlSb.append("<Latitude>23.137466</Latitude>");
xmlSb.append("<Longitude>113.352425</Longitude>");
xmlSb.append("<Precision>119.385040</Precision>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void menu_click() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[CLICK]]></Event>");
xmlSb.append("<EventKey><![CDATA[EVENTKEY]]></EventKey>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void menu_link() {
try {
xmlSb.delete(0, xmlSb.length());
xmlSb.append("<xml>");
xmlSb.append("<ToUserName><![CDATA[toUser]]></ToUserName>");
xmlSb.append("<FromUserName><![CDATA[FromUser]]></FromUserName>");
xmlSb.append("<CreateTime>123456789</CreateTime>");
xmlSb.append("<MsgType><![CDATA[event]]></MsgType>");
xmlSb.append("<Event><![CDATA[VIEW]]></Event>");
xmlSb.append("<EventKey><![CDATA[www.qq.com]]></EventKey>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
}
/***************** common message *********************/
@ -144,7 +29,7 @@ public class MessageInTest {
xmlSb.append("<Content><![CDATA[this is a test]]></Content>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
@ -163,7 +48,7 @@ public class MessageInTest {
xmlSb.append("<MediaId><![CDATA[media_id]]></MediaId>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
@ -182,7 +67,7 @@ public class MessageInTest {
xmlSb.append("<Format><![CDATA[Format]]></Format>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
@ -202,7 +87,7 @@ public class MessageInTest {
xmlSb.append("<Recognition><![CDATA[腾讯微信团队]]></Recognition>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
@ -221,7 +106,7 @@ public class MessageInTest {
xmlSb.append("<ThumbMediaId><![CDATA[thumb_media_id]]></ThumbMediaId>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
@ -242,7 +127,7 @@ public class MessageInTest {
xmlSb.append("<Label><![CDATA[位置信息]]></Label>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}
@ -262,7 +147,7 @@ public class MessageInTest {
xmlSb.append("<Url><![CDATA[url]]></Url>");
xmlSb.append("<MsgId>1234567890123456</MsgId>");
xmlSb.append("</xml>");
System.out.println(weixinProxy.xml2msg(xmlSb.toString()));
System.out.println(MessageUtil.xml2msg(xmlSb.toString()));
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -0,0 +1,114 @@
package com.foxinmy.weixin4j.test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.WeixinProxy;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.MpArticle;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 群发消息
*
* @className MpNewsTest
* @author jy
* @date 2014年4月27日
* @since JDK 1.7
* @see
*/
public class MessageMassTest {
private WeixinProxy weixinProxy;
@Before
public void init() {
this.weixinProxy = new WeixinProxy();
}
@Test
public void uploadArticle() {
List<MpArticle> articles = new ArrayList<MpArticle>();
try {
String thumbMediaId = weixinProxy.uploadMedia(new File(
"/tmp/test.jpg"), MediaType.image);
articles.add(new MpArticle(thumbMediaId, "title", "content"));
weixinProxy.uploadArticle(articles);
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void uploadVideo() {
try {
weixinProxy.uploadVideo("mediaId", "title", "desc");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void massByGroup() {
try {
weixinProxy.massByGroup("123", MediaType.image, "groupId");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void massByOpenIds() {
try {
weixinProxy.massByOpenIds("123", MediaType.image, "openIds");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void massArticleByGroup() {
List<MpArticle> articles = new ArrayList<MpArticle>();
try {
String thumbMediaId = weixinProxy.uploadMedia(new File(
"/tmp/test.jpg"), MediaType.image);
articles.add(new MpArticle(thumbMediaId, "title", "content"));
weixinProxy.massArticleByGroup(articles, "0");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void massArticleByOpenIds() {
List<MpArticle> articles = new ArrayList<MpArticle>();
try {
String thumbMediaId = weixinProxy.uploadMedia(new File(
"/tmp/test.jpg"), MediaType.image);
articles.add(new MpArticle(thumbMediaId, "title", "content"));
weixinProxy.massArticleByOpenIds(articles,
"owGBft_vbBbOaQOmpEUE4xDLeRSU");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void deleteMass() {
try {
weixinProxy.deleteMassNews("34182");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
}

View File

@ -7,6 +7,7 @@ import org.junit.Test;
import com.foxinmy.weixin4j.WeixinProxy;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.msg.model.Music;
import com.foxinmy.weixin4j.msg.notify.ArticleNotify;
import com.foxinmy.weixin4j.msg.notify.BaseNotify;
import com.foxinmy.weixin4j.msg.notify.ImageNotify;
@ -41,27 +42,29 @@ public class MessageNotifyTest {
@Test
public void image() {
ImageNotify notify = new ImageNotify("123", "to");
ImageNotify notify = new ImageNotify("to");
notify.pushMediaId("123");
System.out.println(notify.toJson());
}
@Test
public void voice() {
VoiceNotify notify = new VoiceNotify("123", "to");
VoiceNotify notify = new VoiceNotify("to");
notify.pushMediaId("123");
System.out.println(notify.toJson());
}
@Test
public void video() {
VideoNotify notify = new VideoNotify("to");
notify.pushVideo("123", "title", "desc");
notify.pushVideo("123","m123");
System.out.println(notify.toJson());
}
@Test
public void music() {
MusicNotify notify = new MusicNotify("to");
notify.pushMusic("title", "desc", "url", "hqUrl", "mediaId");
notify.pushMusic("url", "hqUrl", "mediaId");
System.out.println(notify.toJson());
}
@ -74,16 +77,27 @@ public class MessageNotifyTest {
}
@Test
public void send() {
BaseNotify t = new TextNotify("哈哈哈哈", "owGBft_vbBbOaQOmpEUE4xDLeRSU");
public void send1() {
BaseNotify notify = new TextNotify("哈哈哈哈", "owGBft_vbBbOaQOmpEUE4xDLeRSU");
try {
weixinProxy.sendNotify(t);
weixinProxy.sendNotify(notify);
String mediaId = weixinProxy.uploadMedia(new File("D:\\test.jpg"), MediaType.image);
t = new ImageNotify(mediaId, "owGBft_vbBbOaQOmpEUE4xDLeRSU");
ImageNotify t = new ImageNotify("owGBft_vbBbOaQOmpEUE4xDLeRSU");
t.pushMediaId(mediaId);
weixinProxy.sendNotify(t);
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void send2() {
try {
weixinProxy.sendNotify("to",new Music("thumbMediaId"));
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
}

View File

@ -1,7 +1,9 @@
package com.foxinmy.weixin4j.test;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.msg.BaseMessage;
import com.foxinmy.weixin4j.msg.TextMessage;
import com.foxinmy.weixin4j.msg.out.ArticleMessage;
import com.foxinmy.weixin4j.msg.out.ImageMessage;
@ -17,56 +19,52 @@ import com.foxinmy.weixin4j.msg.out.VoiceMessage;
* @since JDK 1.7
*/
public class MessageOutTest {
private BaseMessage inMessage;
@Before
public void init() {
this.inMessage = new TextMessage();
this.inMessage.setFromUserName("fromusername");
this.inMessage.setToUserName("tousername");
}
@Test
public void text() {
TextMessage message = new TextMessage();
message.setFromUserName("fromUser");
message.setToUserName("toUser");
message.setContent("text message");
TextMessage message = new TextMessage("text", inMessage);
System.out.println(message.toXml());
}
@Test
public void image() {
ImageMessage message = new ImageMessage();
message.setFromUserName("fromUser");
message.setToUserName("toUser");
ImageMessage message = new ImageMessage(inMessage);
message.pushMediaId("mediaId");
System.out.println(message.toXml());
}
@Test
public void voice() {
VoiceMessage message = new VoiceMessage();
message.setFromUserName("fromUser");
message.setToUserName("toUser");
VoiceMessage message = new VoiceMessage(inMessage);
message.pushMediaId("mediaId");
System.out.println(message.toXml());
}
@Test
public void video() {
VideoMessage message = new VideoMessage();
message.setFromUserName("fromUser");
message.setToUserName("toUser");
message.pushVideo("mediaId", "title", "title");
VideoMessage message = new VideoMessage(inMessage);
message.pushVideo("mediaId");
System.out.println(message.toXml());
}
@Test
public void music() {
MusicMessage message = new MusicMessage();
message.setFromUserName("fromUser");
message.setToUserName("toUser");
message.pushMusic("title", "desc", "url", "hqurl", "mediaId");
MusicMessage message = new MusicMessage(inMessage);
message.pushMusic("mediaId");
System.out.println(message.toXml());
}
@Test
public void article() {
ArticleMessage message = new ArticleMessage();
message.setFromUserName("fromUser");
message.setToUserName("toUser");
ArticleMessage message = new ArticleMessage(inMessage);
message.pushArticle("title1", "desc1", "picUrl1", "url1");
message.pushArticle("title2", "desc2", "picUrl2", "url2");
System.out.println(message.toXml());

View File

@ -0,0 +1,30 @@
package com.foxinmy.weixin4j.test;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.WeixinProxy;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.msg.out.TemplateMessage;
public class MessageTemplTest {
private WeixinProxy weixinProxy;
@Before
public void init() {
this.weixinProxy = new WeixinProxy();
}
@Test
public void test() {
TemplateMessage tplMessage = new TemplateMessage("touser",
"template_id", "url");
tplMessage.pushData("name", "fox");
System.out.print(tplMessage.toJson());
try {
System.out.print(weixinProxy.sendTplMessage(tplMessage));
} catch (WeixinException e) {
System.out.println(e.getErrorMsg());
}
}
}

View File

@ -1,67 +0,0 @@
package com.foxinmy.weixin4j.test;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.WeixinProxy;
import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.MpArticle;
import com.foxinmy.weixin4j.type.MediaType;
/**
* 群发消息
*
* @className MpNewsTest
* @author jy
* @date 2014年4月27日
* @since JDK 1.7
* @see
*/
public class MpNewsTest {
private WeixinProxy weixinProxy;
@Before
public void init() {
this.weixinProxy = new WeixinProxy();
}
@Test
public void massByGroup(){
List<MpArticle> articles = new ArrayList<MpArticle>();
try {
String thumbMediaId = weixinProxy.uploadMedia(new File("/tmp/test.jpg"), MediaType.image);
articles.add(new MpArticle(thumbMediaId, "title", "content"));
weixinProxy.massNewsByGroup(articles, "0");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void massByOpenIds(){
List<MpArticle> articles = new ArrayList<MpArticle>();
try {
String thumbMediaId = weixinProxy.uploadMedia(new File("/tmp/test.jpg"), MediaType.image);
articles.add(new MpArticle(thumbMediaId, "title", "content"));
weixinProxy.massNewsByOpenIds(articles, "owGBft_vbBbOaQOmpEUE4xDLeRSU");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
@Test
public void deleteMass(){
try {
weixinProxy.deleteMassNews("34182");
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
}
}
}

View File

@ -25,10 +25,10 @@ public class QRTest {
@Test
public void temp_qr() {
QRParameter qr = new QRParameter(1200, QRType.QR_SCENE, 1);
QRParameter qr = new QRParameter(1200, QRType.TEMPORARY, 2);
try {
System.out.println(qr.toJson());
weixinProxy.getQR(qr);
System.out.println(weixinProxy.getQR(qr));
} catch (WeixinException e) {
System.out.println(e.getErrorCode());
System.out.println(e.getErrorMsg());
@ -37,10 +37,10 @@ public class QRTest {
@Test
public void forever_qr() {
QRParameter qr = new QRParameter(QRType.QR_LIMIT_SCENE, 1);
QRParameter qr = new QRParameter(QRType.PERMANENCE, 1);
try {
System.out.println(qr.toJson());
weixinProxy.getQR(qr);
System.out.println(weixinProxy.getQR(qr));
} catch (Exception e) {
e.printStackTrace();
}

View File

@ -3,7 +3,8 @@ package com.foxinmy.weixin4j.test;
import org.junit.Before;
import org.junit.Test;
import com.foxinmy.weixin4j.WeixinProxy;
import com.foxinmy.weixin4j.api.token.FileTokenApi;
import com.foxinmy.weixin4j.api.token.TokenApi;
import com.foxinmy.weixin4j.exception.WeixinException;
/**
@ -14,17 +15,17 @@ import com.foxinmy.weixin4j.exception.WeixinException;
* @since JDK 1.7
*/
public class TokenTest {
private WeixinProxy weixinProxy;
private TokenApi tokenApi;
@Before
public void init() {
weixinProxy = new WeixinProxy();
tokenApi = new FileTokenApi();
}
@Test
public void getToken() {
try {
System.out.println(weixinProxy.getToken());
System.out.println(tokenApi.getToken());
} catch (WeixinException e) {
e.printStackTrace();
}