From 82cc58964046c47580d1c9ec985b07c94de457d0 Mon Sep 17 00:00:00 2001 From: jinyu Date: Sat, 4 Jul 2015 18:28:24 +0800 Subject: [PATCH] =?UTF-8?q?weixin4j-qy:=E6=96=B0=E5=A2=9E=E5=AA=92?= =?UTF-8?q?=E4=BD=93=E7=B4=A0=E6=9D=90=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGE.md | 6 +- .../com/foxinmy/weixin4j/api/BaseApi.java | 30 +- .../weixin4j/http/SimpleHttpClient.java | 12 +- .../weixin4j/http/apache/InputStreamBody.java | 92 +++-- .../foxinmy/weixin4j}/model/MediaCounter.java | 31 +- .../foxinmy/weixin4j}/model/MediaItem.java | 4 +- .../foxinmy/weixin4j}/model/MediaRecord.java | 2 +- .../weixin4j/payment/WeixinPayProxy.java | 4 +- .../weixin4j/token/FileTokenStorager.java | 5 - .../java/com/foxinmy/weixin4j/tuple/Card.java | 2 +- .../com/foxinmy/weixin4j/util/ConfigUtil.java | 38 ++ .../foxinmy/weixin4j/util/Weixin4jConst.java | 33 ++ .../com/foxinmy/weixin4j/mp/WeixinProxy.java | 55 +-- .../com/foxinmy/weixin4j/mp/api/MassApi.java | 15 +- .../com/foxinmy/weixin4j/mp/api/MediaApi.java | 93 +++-- .../com/foxinmy/weixin4j/mp/api/MpApi.java | 4 +- .../com/foxinmy/weixin4j/mp/api/QrApi.java | 4 +- .../foxinmy/weixin4j/mp/api/weixin.properties | 4 +- .../foxinmy/weixin4j/mp/test/MassTest.java | 2 +- .../foxinmy/weixin4j/mp/test/MediaTest.java | 19 +- .../com/foxinmy/weixin4j/mp/test/PayTest.java | 4 +- .../foxinmy/weixin4j/mp/test/TokenTest.java | 3 +- weixin4j-qy/CHANGE.md | 6 +- .../com/foxinmy/weixin4j/qy/WeixinProxy.java | 202 ++++++++-- .../com/foxinmy/weixin4j/qy/api/MediaApi.java | 367 ++++++++++++++---- .../com/foxinmy/weixin4j/qy/api/QyApi.java | 4 +- .../com/foxinmy/weixin4j/qy/api/UserApi.java | 2 +- .../foxinmy/weixin4j/qy/api/weixin.properties | 21 +- .../com/foxinmy/weixin4j/qy/model/User.java | 15 +- .../foxinmy/weixin4j/qy/test/MediaTest.java | 13 +- .../foxinmy/weixin4j/qy/test/TokenTest.java | 3 +- .../foxinmy/weixin4j/qy/test/UserTest.java | 5 +- .../startup/WeixinServerBootstrap.java | 2 +- 33 files changed, 820 insertions(+), 282 deletions(-) rename {weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp => weixin4j-base/src/main/java/com/foxinmy/weixin4j}/model/MediaCounter.java (67%) rename {weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp => weixin4j-base/src/main/java/com/foxinmy/weixin4j}/model/MediaItem.java (95%) rename {weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp => weixin4j-base/src/main/java/com/foxinmy/weixin4j}/model/MediaRecord.java (97%) create mode 100644 weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConst.java diff --git a/CHANGE.md b/CHANGE.md index b5fd93a3..648093e9 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -361,4 +361,8 @@ * 2015-06-27 - + 媒体接口(MediaApi)中上传方法中的File类型调整为InputStream \ No newline at end of file + + 媒体接口(MediaApi)中上传方法中的File类型调整为InputStream + +* 2015-07-04 + + + **weixin4j-qy**: 新增[媒体素材接口](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java) \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java index 494d09cb..59f65e5a 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/api/BaseApi.java @@ -1,14 +1,16 @@ package com.foxinmy.weixin4j.api; +import java.util.MissingResourceException; +import java.util.ResourceBundle; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.alibaba.fastjson.JSON; import com.foxinmy.weixin4j.http.weixin.WeixinHttpClient; import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.util.ConfigUtil; +import com.foxinmy.weixin4j.util.Weixin4jConst; /** * API基础 @@ -22,12 +24,16 @@ import com.foxinmy.weixin4j.util.ConfigUtil; */ public abstract class BaseApi { - protected final WeixinHttpClient weixinClient = new WeixinHttpClient(); + protected final WeixinHttpClient weixinClient; - protected abstract String getConfigValue(String key); + protected abstract ResourceBundle weixinBundle(); + + public BaseApi() { + this.weixinClient = new WeixinHttpClient(); + } protected String getRequestUri(String key) { - String url = getConfigValue(key); + String url = weixinBundle().getString(key); Pattern p = Pattern.compile("(\\{[^\\}]*\\})"); Matcher m = p.matcher(url); StringBuffer sb = new StringBuffer(); @@ -44,16 +50,22 @@ public abstract class BaseApi { /** * 默认使用weixin4j.properties文件中的公众号信息 */ - public final static WeixinAccount DEFAULT_WEIXIN_ACCOUNT; + public static WeixinAccount DEFAULT_WEIXIN_ACCOUNT; /** * 默认token使用File的方式存储 */ - public final static TokenStorager DEFAULT_TOKEN_STORAGER; + public static TokenStorager DEFAULT_TOKEN_STORAGER; static { - DEFAULT_WEIXIN_ACCOUNT = JSON.parseObject( - ConfigUtil.getValue("account"), WeixinAccount.class); - DEFAULT_TOKEN_STORAGER = new FileTokenStorager(); + try { + DEFAULT_WEIXIN_ACCOUNT = ConfigUtil.getWeixinAccount(); + } catch (MissingResourceException e) { + System.err + .println("'account' key not found in weixin4j.properties file."); + ; // error + } + DEFAULT_TOKEN_STORAGER = new FileTokenStorager(ConfigUtil.getValue( + "token_path", Weixin4jConst.DEFAULT_TOKEN_PATH)); } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/SimpleHttpClient.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/SimpleHttpClient.java index 108d2bf1..910cf4c0 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/SimpleHttpClient.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/SimpleHttpClient.java @@ -128,10 +128,14 @@ public class SimpleHttpClient implements HttpClient { httpEntity = ((HttpEntityRequest) request).getEntity(); connection.setUseCaches(false); if (httpEntity != null) { - connection.setFixedLengthStreamingMode(httpEntity - .getContentLength()); - connection.setRequestProperty("Content-Type", httpEntity - .getContentType().getMimeType()); + if (httpEntity.getContentLength() > 0l) { + connection.setFixedLengthStreamingMode(httpEntity + .getContentLength()); + } + if (httpEntity.getContentType() != null) { + connection.setRequestProperty("Content-Type", httpEntity + .getContentType().getMimeType()); + } } } connection.connect(); diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/apache/InputStreamBody.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/apache/InputStreamBody.java index b01c235f..75ffb9ba 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/apache/InputStreamBody.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/apache/InputStreamBody.java @@ -37,56 +37,62 @@ import java.io.OutputStream; */ public class InputStreamBody extends AbstractContentBody { - private final InputStream in; - private final String filename; + private final InputStream in; + private final String filename; - public InputStreamBody(final InputStream in, final String mimeType, final String filename) { - super(mimeType); - if (in == null) { - throw new IllegalArgumentException("Input stream may not be null"); - } - this.in = in; - this.filename = filename; - } + public InputStreamBody(final InputStream in, final String mimeType, + final String filename) { + super(mimeType); + if (in == null) { + throw new IllegalArgumentException("Input stream may not be null"); + } + this.in = in; + this.filename = filename; + } - public InputStreamBody(final InputStream in, final String filename) { - this(in, "application/octet-stream", filename); - } + public InputStreamBody(final InputStream in, final String filename) { + this(in, "application/octet-stream", filename); + } - public InputStream getInputStream() { - return this.in; - } + public InputStream getInputStream() { + return this.in; + } - public void writeTo(final OutputStream out) throws IOException { - if (out == null) { - throw new IllegalArgumentException("Output stream may not be null"); - } - try { - byte[] tmp = new byte[4096]; - int l; - while ((l = this.in.read(tmp)) != -1) { - out.write(tmp, 0, l); - } - out.flush(); - } finally { - this.in.close(); - } - } + public void writeTo(final OutputStream out) throws IOException { + if (out == null) { + throw new IllegalArgumentException("Output stream may not be null"); + } + try { + byte[] tmp = new byte[4096]; + int l; + while ((l = this.in.read(tmp)) != -1) { + out.write(tmp, 0, l); + } + out.flush(); + } finally { + this.in.close(); + } + } - public String getTransferEncoding() { - return MIME.ENC_BINARY; - } + public String getTransferEncoding() { + return MIME.ENC_BINARY; + } - public String getCharset() { - return null; - } + public String getCharset() { + return null; + } - public long getContentLength() { - return -1; - } + public long getContentLength() { + try { + return in.available(); + } catch (IOException e) { + ; + } + return -1; + } - public String getFilename() { - return this.filename; - } + public String getFilename() { + return this.filename; + } } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaCounter.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaCounter.java similarity index 67% rename from weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaCounter.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaCounter.java index a5ca3314..b99721fe 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaCounter.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaCounter.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.mp.model; +package com.foxinmy.weixin4j.model; import java.io.Serializable; @@ -17,6 +17,16 @@ public class MediaCounter implements Serializable { private static final long serialVersionUID = -1752502821323552783L; + /** + * 应用素材总数目(企业号独有) + */ + @JSONField(name = "total_count") + private int totalCount; + /** + * 文件素材总数目(企业号都有) + */ + @JSONField(name = "file_count") + private int fileCount; /** * 语音总数量 */ @@ -70,9 +80,26 @@ public class MediaCounter implements Serializable { this.newsCount = newsCount; } + public int getTotalCount() { + return totalCount; + } + + public void setTotalCount(int totalCount) { + this.totalCount = totalCount; + } + + public int getFileCount() { + return fileCount; + } + + public void setFileCount(int fileCount) { + this.fileCount = fileCount; + } + @Override public String toString() { - return "MediaCounter [voiceCount=" + voiceCount + ", videoCount=" + return "MediaCounter [totalCount=" + totalCount + ", fileCount=" + + fileCount + ", voiceCount=" + voiceCount + ", videoCount=" + videoCount + ", imageCount=" + imageCount + ", newsCount=" + newsCount + "]"; } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaItem.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaItem.java similarity index 95% rename from weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaItem.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaItem.java index 4cba031d..6383929d 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaItem.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaItem.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.mp.model; +package com.foxinmy.weixin4j.model; import java.io.Serializable; import java.util.Date; @@ -37,7 +37,7 @@ public class MediaItem implements Serializable { /** * 图文素材列表 */ - @JSONField(name = "news_item") + @JSONField(name = "articles") private List articles; public String getMediaId() { diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaRecord.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaRecord.java similarity index 97% rename from weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaRecord.java rename to weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaRecord.java index f0d56b7f..89621aae 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/model/MediaRecord.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/model/MediaRecord.java @@ -1,4 +1,4 @@ -package com.foxinmy.weixin4j.mp.model; +package com.foxinmy.weixin4j.model; import java.io.Serializable; import java.util.List; diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java index f53bd50e..88f4d943 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/payment/WeixinPayProxy.java @@ -26,6 +26,7 @@ import com.foxinmy.weixin4j.type.BillType; import com.foxinmy.weixin4j.type.CurrencyType; import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.util.ConfigUtil; +import com.foxinmy.weixin4j.util.Weixin4jConst; /** * 微信支付接口实现 @@ -64,7 +65,8 @@ public class WeixinPayProxy { this.pay3Api = new Pay3Api(weixinAccount); this.couponApi = new CouponApi(weixinAccount); this.cashApi = new CashApi(weixinAccount); - this.DEFAULT_CA_FILE = new File(ConfigUtil.getClassPathValue("ca_file")); + this.DEFAULT_CA_FILE = new File(ConfigUtil.getClassPathValue("ca_file", + Weixin4jConst.DEFAULT_MEDIA_PATH)); } /** diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java index f44124cb..92575c49 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/token/FileTokenStorager.java @@ -7,7 +7,6 @@ import java.io.IOException; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.xml.XmlStream; /** @@ -22,10 +21,6 @@ public class FileTokenStorager implements TokenStorager { private final String cachePath; - public FileTokenStorager() { - this(ConfigUtil.getValue("token_path")); - } - public FileTokenStorager(String cachePath) { this.cachePath = cachePath; } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/tuple/Card.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/tuple/Card.java index 1941ed08..f0025547 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/tuple/Card.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/tuple/Card.java @@ -17,7 +17,7 @@ import com.alibaba.fastjson.annotation.JSONField; * @see */ public class Card implements MassTuple { - + private static final long serialVersionUID = 6119453633595102147L; @Override diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ConfigUtil.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ConfigUtil.java index c9423d44..7ef51a55 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ConfigUtil.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ConfigUtil.java @@ -1,6 +1,7 @@ package com.foxinmy.weixin4j.util; import java.io.File; +import java.util.MissingResourceException; import java.util.ResourceBundle; import java.util.Set; @@ -49,6 +50,25 @@ public class ConfigUtil { return weixinBundle.getString(key); } + /** + * key不存在时则返回传入的默认值 + * + * @param key + * @param defaultValue + * @return + */ + public static String getValue(String key, String defaultValue) { + String value = defaultValue; + try { + value = weixinBundle.getString(key); + } catch (MissingResourceException e) { + System.err.println("'" + key + + "' key not found in weixin4j.properties file."); + ; // error + } + return value; + } + /** * 判断属性是否存在[classpath:]如果存在则拼接项目路径后返回 一般用于文件的绝对路径获取 * @@ -60,6 +80,24 @@ public class ConfigUtil { CLASSPATH_VALUE)).getPath(); } + /** + * + * @param key + * @param defaultValue + * @return + */ + public static String getClassPathValue(String key, String defaultValue) { + String value = defaultValue; + try { + value = getClassPathValue(key); + } catch (MissingResourceException e) { + System.err.println("'" + key + + "' key not found in weixin4j.properties file."); + ; // error + } + return value; + } + public static WeixinAccount getWeixinAccount() { String text = getValue("account"); return JSON.parseObject(text, WeixinAccount.class); diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConst.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConst.java new file mode 100644 index 00000000..80cd58ab --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/Weixin4jConst.java @@ -0,0 +1,33 @@ +package com.foxinmy.weixin4j.util; + +/** + * 常量配置 + * + * @className Weixin4jConst + * @author jy + * @date 2015年7月1日 + * @since JDK 1.7 + * @see + */ +public final class Weixin4jConst { + /** + * 使用FileTokenStorager时token的存放路径 + */ + public static final String DEFAULT_TOKEN_PATH = "/tmp/weixin4j/token"; + /** + * 二维码保存路径 + */ + public static final String DEFAULT_QRCODE_PATH = "/tmp/weixin4j/qrcode"; + /** + * 媒体文件保存路径 + */ + public static final String DEFAULT_MEDIA_PATH = "/tmp/weixin4j/media"; + /** + * 对账单保存路径 + */ + public static final String DEFAULT_BILL_PATH = "/tmp/weixin4j/bill"; + /** + * ca证书存放的完整路径 (V2版本后缀为*.pfx,V3版本后缀为*.p12) + */ + public static final String DEFAULT_CAFILE_PATH = "classpath:ca.p12"; +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index bae9f6de..46810e1d 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -9,6 +9,9 @@ import java.util.List; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.model.Button; +import com.foxinmy.weixin4j.model.MediaCounter; +import com.foxinmy.weixin4j.model.MediaItem; +import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.mp.api.CustomApi; import com.foxinmy.weixin4j.mp.api.DataApi; import com.foxinmy.weixin4j.mp.api.GroupApi; @@ -29,9 +32,6 @@ import com.foxinmy.weixin4j.mp.model.Following; import com.foxinmy.weixin4j.mp.model.Group; import com.foxinmy.weixin4j.mp.model.KfAccount; import com.foxinmy.weixin4j.mp.model.KfSession; -import com.foxinmy.weixin4j.mp.model.MediaCounter; -import com.foxinmy.weixin4j.mp.model.MediaItem; -import com.foxinmy.weixin4j.mp.model.MediaRecord; import com.foxinmy.weixin4j.mp.model.MenuSetting; import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.SemQuery; @@ -134,7 +134,7 @@ public class WeixinProxy { * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#uploadMedia(InputStream, MediaType,boolean)} - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @throws WeixinException * @throws IOException */ @@ -162,7 +162,7 @@ public class WeixinProxy { * @see 上传永久素材 * @see com.foxinmy.weixin4j.type.MediaType - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @throws WeixinException */ public String uploadMedia(InputStream is, MediaType mediaType, @@ -186,7 +186,7 @@ public class WeixinProxy { * @throws WeixinException * @see 上传下载说明 - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#downloadMedia(String)} */ public File downloadMediaFile(String mediaId, boolean isMaterial) @@ -203,7 +203,7 @@ public class WeixinProxy { * 是否永久素材 * @return 二进制数据包 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @see 上传下载说明 */ @@ -223,7 +223,7 @@ public class WeixinProxy { * 图文列表 * @return 上传到微信服务器返回的媒体标识 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @see com.foxinmy.weixin4j.tuple.MpArticle * @see 上传永久媒体素材 @@ -243,7 +243,7 @@ public class WeixinProxy { * @see 下载永久媒体素材 * @see com.foxinmy.weixin4j.tuple.MpArticle - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi */ public List downloadArticle(String mediaId) throws WeixinException { @@ -261,7 +261,7 @@ public class WeixinProxy { * 图文列表 * @return 处理结果 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @see com.foxinmy.weixin4j.tuple.MpArticle * @see 更新永久图文素材 @@ -278,7 +278,7 @@ public class WeixinProxy { * 媒体素材的media_id * @return 处理结果 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @see 删除永久媒体素材 */ @@ -290,7 +290,7 @@ public class WeixinProxy { /** * 上传永久视频素材 * - * @param file + * @param is * 大小不超过1M且格式为MP4的视频文件 * @param title * 视频标题 @@ -299,13 +299,12 @@ public class WeixinProxy { * @return 上传到微信服务器返回的媒体标识 * @see 上传永久媒体素材 - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @throws WeixinException - * @throws IOException */ - public String uploadMaterialVideo(File file, String title, - String introduction) throws WeixinException, IOException { - return mediaApi.uploadMaterialVideo(file, title, introduction); + public String uploadMaterialVideo(InputStream is, String title, + String introduction) throws WeixinException { + return mediaApi.uploadMaterialVideo(is, title, introduction); } /** @@ -316,7 +315,7 @@ public class WeixinProxy { * @see com.foxinmy.weixin4j.mp.model.MediaCounter * @see 获取素材总数 - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi */ public MediaCounter countMaterialMedia() throws WeixinException { return mediaApi.countMaterialMedia(); @@ -333,7 +332,7 @@ public class WeixinProxy { * 返回素材的数量,取值在1到20之间 * @return 媒体素材的记录对象 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @see com.foxinmy.weixin4j.mp.model.MediaRecord * @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.mp.model.MediaItem @@ -351,7 +350,7 @@ public class WeixinProxy { * @param mediaType * 媒体类型 * @return 素材列表 - * @see com.foxinmy.weixin4j.mp.api.MediaApi + * @see com.com.foxinmy.weixin4j.mp.api.MediaApi * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#listMaterialMedia(MediaType, int, int)} * @throws WeixinException */ @@ -651,7 +650,7 @@ public class WeixinProxy { * @see com.foxinmy.weixin4j.mp.api.MassApi * @see com.foxinmy.weixin4j.tuple.Video * @see com.foxinmy.weixin4j.tuple.MpVideo - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} + * @see {@link com.com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} */ public String uploadMassVideo(Video video) throws WeixinException { return massApi.uploadVideo(video); @@ -749,7 +748,7 @@ public class WeixinProxy { * @see com.foxinmy.weixin4j.tuple.MassTuple * @see 根据openid群发 - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} + * @see {@link com.com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} * @see {@link com.foxinmy.weixin4j.mp.api.UserApi#getUser(String)} */ public String massByOpenIds(MassTuple tuple, String... openIds) @@ -798,8 +797,10 @@ public class WeixinProxy { /** * 预览群发消息
开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版 * - * @param openId - * 接收用户的ID + * @param toUser + * 接收用户的openID + * @param toWxName + * 接收用户的微信号 towxname和touser同时赋值时,以towxname优先 * @param tuple * 消息元件 * @return 处理结果 @@ -809,9 +810,9 @@ public class WeixinProxy { * @see 预览群发消息 */ - public JsonResult previewMassNews(String openId, MassTuple tuple) - throws WeixinException { - return massApi.previewMassNews(openId, tuple); + public JsonResult previewMassNews(String toUser, String toWxName, + MassTuple tuple) throws WeixinException { + return massApi.previewMassNews(toUser, toWxName, tuple); } /** diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java index bb68a32d..7a5ce304 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MassApi.java @@ -73,7 +73,7 @@ public class MassApi extends MpApi { * href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html">高级群发 * @see com.foxinmy.weixin4j.tuple.Video * @see com.foxinmy.weixin4j.tuple.MpVideo - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} + * @see {@link com.com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File)} */ public String uploadVideo(Video video) throws WeixinException { String video_upload_uri = getRequestUri("video_upload_uri"); @@ -274,8 +274,10 @@ public class MassApi extends MpApi { /** * 预览群发消息
开发者可通过该接口发送消息给指定用户,在手机端查看消息的样式和排版 * - * @param openId - * 接收用户的ID + * @param toUser + * 接收用户的openID + * @param toWxName + * 接收用户的微信号 towxname和touser同时赋值时,以towxname优先 * @param tuple * 消息元件 * @return 处理结果 @@ -284,11 +286,12 @@ public class MassApi extends MpApi { * @see 预览群发消息 */ - public JsonResult previewMassNews(String openId, MassTuple tuple) - throws WeixinException { + public JsonResult previewMassNews(String toUser, String toWxName, + MassTuple tuple) throws WeixinException { String msgtype = tuple.getMessageType(); JSONObject obj = new JSONObject(); - obj.put("touser", openId); + obj.put("touser", toUser); + obj.put("towxname", toWxName); obj.put(msgtype, JSON.toJSON(tuple)); obj.put("msgtype", msgtype); String mass_preview_uri = getRequestUri("mass_preview_uri"); diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MediaApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MediaApi.java index 3c5b8fc7..e9910638 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MediaApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MediaApi.java @@ -15,17 +15,19 @@ import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.parser.deserializer.ExtraProcessor; import com.foxinmy.weixin4j.exception.WeixinException; -import com.foxinmy.weixin4j.http.apache.ByteArrayBody; +import com.foxinmy.weixin4j.http.HttpGet; +import com.foxinmy.weixin4j.http.HttpPost; import com.foxinmy.weixin4j.http.apache.FormBodyPart; import com.foxinmy.weixin4j.http.apache.InputStreamBody; import com.foxinmy.weixin4j.http.apache.StringBody; +import com.foxinmy.weixin4j.http.entity.StringEntity; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Consts; +import com.foxinmy.weixin4j.model.MediaCounter; +import com.foxinmy.weixin4j.model.MediaItem; +import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.model.Token; -import com.foxinmy.weixin4j.mp.model.MediaCounter; -import com.foxinmy.weixin4j.mp.model.MediaItem; -import com.foxinmy.weixin4j.mp.model.MediaRecord; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.type.MediaType; @@ -34,6 +36,7 @@ import com.foxinmy.weixin4j.util.FileUtil; import com.foxinmy.weixin4j.util.IOUtil; import com.foxinmy.weixin4j.util.ObjectId; import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.util.Weixin4jConst; /** * 素材相关API @@ -73,12 +76,12 @@ public class MediaApi extends MpApi { MediaType mediaType = null; if ("bmp/png/jpeg/jpg/gif".contains(mediaTypeKey)) { mediaType = MediaType.image; - } else if ("amr/mp3".contains(mediaTypeKey)) { + } else if ("mp3/wma/wav/amr".contains(mediaTypeKey)) { mediaType = MediaType.voice; - } else if ("mp3/wma/wav/amr".equals(mediaTypeKey)) { + } else if ("mp4".equals(mediaTypeKey)) { mediaType = MediaType.video; } else { - throw new WeixinException("unknown mediaType:" + mediaTypeKey); + throw new WeixinException("cannot handle mediaType:" + mediaTypeKey); } return uploadMedia(new FileInputStream(file), mediaType, isMaterial); } @@ -102,7 +105,6 @@ public class MediaApi extends MpApi { * @see 上传永久素材 * @see com.foxinmy.weixin4j.type.MediaType - * @see com.foxinmy.weixin4j.mp.api.MediaApi * @throws WeixinException */ public String uploadMedia(InputStream is, MediaType mediaType, @@ -125,12 +127,12 @@ public class MediaApi extends MpApi { new FormBodyPart("type", new StringBody(mediaType .name(), Consts.UTF_8))); } else { - String file_upload_uri = getRequestUri("file_upload_uri"); - response = weixinClient.post(String.format(file_upload_uri, - token.getAccessToken(), mediaType), new FormBodyPart( - "media", new InputStreamBody(is, mediaType - .getContentType().getMimeType(), ObjectId.get() - .toHexString()))); + String media_upload_uri = getRequestUri("media_upload_uri"); + response = weixinClient.post(String.format(media_upload_uri, + token.getAccessToken(), mediaType.name()), + new FormBodyPart("media", new InputStreamBody(is, + mediaType.getContentType().getMimeType(), + ObjectId.get().toHexString()))); } } catch (UnsupportedEncodingException e) { throw new WeixinException(e); @@ -162,7 +164,8 @@ public class MediaApi extends MpApi { */ public File downloadMediaFile(String mediaId, boolean isMaterial) throws WeixinException { - String media_path = ConfigUtil.getValue("media_path"); + String media_path = ConfigUtil.getValue("media_path", + Weixin4jConst.DEFAULT_MEDIA_PATH); File file = new File(media_path + File.separator + mediaId); if (file.exists()) { return file; @@ -198,7 +201,7 @@ public class MediaApi extends MpApi { * 媒体ID * @param isMaterial * 是否下载永久素材 - * @return 二进制数据包 + * @return 二进制数据包(需自行判断类型) * @throws WeixinException * @see 下载临时媒体素材 @@ -208,20 +211,23 @@ public class MediaApi extends MpApi { public byte[] downloadMedia(String mediaId, boolean isMaterial) throws WeixinException { Token token = tokenHolder.getToken(); - WeixinResponse response = null; - if (isMaterial) { - JSONObject media = new JSONObject(); - media.put("media_id", mediaId); - String material_media_download_uri = getRequestUri("material_media_download_uri"); - response = weixinClient.post( - String.format(material_media_download_uri, - token.getAccessToken()), media.toJSONString()); - } else { - String file_download_uri = getRequestUri("file_download_uri"); - response = weixinClient.get(String.format(file_download_uri, - token.getAccessToken(), mediaId)); + try { + if (isMaterial) { + String material_media_download_uri = getRequestUri("material_media_download_uri"); + HttpPost method = new HttpPost(String.format( + material_media_download_uri, token.getAccessToken())); + method.setEntity(new StringEntity(String.format( + "{\"media_id\":\"%s\"}", mediaId))); + return weixinClient.execute(method).getContent(); + } else { + String meida_download_uri = getRequestUri("meida_download_uri"); + HttpGet method = new HttpGet(String.format(meida_download_uri, + token.getAccessToken(), mediaId)); + return weixinClient.execute(method).getContent(); + } + } catch (IOException e) { + throw new WeixinException(e); } - return response.getContent(); } /** @@ -327,7 +333,7 @@ public class MediaApi extends MpApi { /** * 上传永久视频素材 * - * @param file + * @param is * 大小不超过1M且格式为MP4的视频文件 * @param title * 视频标题 @@ -337,29 +343,36 @@ public class MediaApi extends MpApi { * @see 上传永久媒体素材 * @throws WeixinException - * @throws IOException */ - public String uploadMaterialVideo(File file, String title, - String introduction) throws WeixinException, IOException { + public String uploadMaterialVideo(InputStream is, String title, + String introduction) throws WeixinException { String material_media_upload_uri = getRequestUri("material_media_upload_uri"); Token token = tokenHolder.getToken(); try { JSONObject description = new JSONObject(); description.put("title", title); description.put("introduction", introduction); - byte[] bytes = IOUtil.toByteArray(new FileInputStream(file)); WeixinResponse response = weixinClient.post( String.format(material_media_upload_uri, token.getAccessToken()), - new FormBodyPart("media", new ByteArrayBody(bytes, file - .getName())), + new FormBodyPart("media", new InputStreamBody(is, + MediaType.video.getContentType().getMimeType(), + ObjectId.get().toHexString())), new FormBodyPart("type", new StringBody(MediaType.video .name(), Consts.UTF_8)), new FormBodyPart("description", new StringBody(description .toJSONString(), Consts.UTF_8))); return response.getAsJson().getString("media_id"); } catch (UnsupportedEncodingException e) { - throw new WeixinException("unsupported encoding"); + throw new WeixinException(e); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + ; + } + } } } @@ -368,7 +381,7 @@ public class MediaApi extends MpApi { * * @return 总数对象 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.model.MediaCounter + * @see com.foxinmy.weixin4j.model.MediaCounter * @see 获取素材总数 */ @@ -393,9 +406,9 @@ public class MediaApi extends MpApi { * 返回素材的数量,取值在1到20之间 * @return 媒体素材的记录对象 * @throws WeixinException - * @see com.foxinmy.weixin4j.mp.model.MediaRecord + * @see com.foxinmy.weixin4j.model.MediaRecord * @see com.foxinmy.weixin4j.type.MediaType - * @see com.foxinmy.weixin4j.mp.model.MediaItem + * @see com.foxinmy.weixin4j.model.MediaItem * @see 获取素材列表 */ diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java index db8ec7f2..7ea99c2a 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/MpApi.java @@ -24,7 +24,7 @@ public class MpApi extends BaseApi { } @Override - protected String getConfigValue(String key) { - return WEIXIN_BUNDLE.getString(key); + protected ResourceBundle weixinBundle() { + return WEIXIN_BUNDLE; } } diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java index 5f0f1ae6..91e5aab0 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/QrApi.java @@ -12,6 +12,7 @@ import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.util.ConfigUtil; +import com.foxinmy.weixin4j.util.Weixin4jConst; /** * 二维码相关API @@ -89,7 +90,8 @@ public class QrApi extends MpApi { * @see com.foxinmy.weixin4j.mp.model.QRParameter */ public File getQRFile(QRParameter parameter) throws WeixinException { - String qr_path = ConfigUtil.getValue("qr_path"); + String qr_path = ConfigUtil.getValue("qr_path", + Weixin4jConst.DEFAULT_QRCODE_PATH); String filename = String.format("%s_%s_%d.jpg", parameter.getQrType() .name(), parameter.getSceneValue(), parameter .getExpireSeconds()); diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties index e07d455c..a2688195 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/api/weixin.properties @@ -30,9 +30,9 @@ api_token_uri={api_cgi_url}/token?grant_type=client_credential&appid=%s&secret=% qr_ticket_uri={api_cgi_url}/qrcode/create?access_token=%s qr_image_uri={mp_base_url}/showqrcode?ticket=%s # \u4e0a\u4f20\u5a92\u4f53\u6587\u4ef6 -file_upload_uri={file_base_url}/media/upload?access_token=%s&type=%s +media_upload_uri={file_base_url}/media/upload?access_token=%s&type=%s # \u4e0b\u8f7d\u5a92\u4f53\u6587\u4ef6 -file_download_uri={file_base_url}/media/get?access_token=%s&media_id=%s +meida_download_uri={file_base_url}/media/get?access_token=%s&media_id=%s # \u53d1\u9001\u5ba2\u670d\u6d88\u606f custom_notify_uri={api_cgi_url}/message/custom/send?access_token=%s # \u521b\u5efa\u5206\u7ec4 diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MassTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MassTest.java index 1e53d636..e4b24622 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MassTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MassTest.java @@ -96,7 +96,7 @@ public class MassTest extends TokenTest { @Test public void previewMass() throws WeixinException { JsonResult result = massApi.previewMassNews( - "oyFLst1bqtuTcxK-ojF8hOGtLQao", new Text("test")); + "oyFLst1bqtuTcxK-ojF8hOGtLQao", null, new Text("test")); Assert.assertEquals(0, result.getCode()); } diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java index 9c0c09d1..1d5dd273 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java @@ -1,6 +1,7 @@ package com.foxinmy.weixin4j.mp.test; import java.io.File; +import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -11,10 +12,10 @@ import org.junit.Test; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.JsonResult; +import com.foxinmy.weixin4j.model.MediaCounter; +import com.foxinmy.weixin4j.model.MediaItem; +import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.mp.api.MediaApi; -import com.foxinmy.weixin4j.mp.model.MediaCounter; -import com.foxinmy.weixin4j.mp.model.MediaItem; -import com.foxinmy.weixin4j.mp.model.MediaRecord; import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.type.MediaType; @@ -47,11 +48,9 @@ public class MediaTest extends TokenTest { @Test public void download1() throws WeixinException, IOException { - File file = mediaApi - .downloadMediaFile( - "1Vgd1R5DdznSc3rPxd-sNZ3pLt54cejhJ5ItuNcCgrqoQArNANWy5oxso_r9KNlE", - false); - Assert.assertTrue(file.exists()); + byte[] content = mediaApi.downloadMedia( + "jM5OWhnYb2DgrNm97HGj8aUdsZcweQc93tnwbH1mERo", true); + Assert.assertTrue(content != null); } @Test @@ -66,8 +65,8 @@ public class MediaTest extends TokenTest { @Test public void uploadMaterialVideo() throws IOException, WeixinException { File file = new File("/Users/jy/Downloads/test.jpg"); - String mediaId = mediaApi.uploadMaterialVideo(file, "title", - "introduction"); + String mediaId = mediaApi.uploadMaterialVideo( + new FileInputStream(file), "title", "introduction"); // Sy1KOLsi4ri3kB3TYUuculVelcW2I7W6BrfGwkGvSW8beTCAarxuGQLjuNJChJr8 Assert.assertNotNull(mediaId); System.err.println(mediaId); diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java index 16790caa..a39b29ba 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/PayTest.java @@ -22,6 +22,7 @@ import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdType; import com.foxinmy.weixin4j.type.TradeType; +import com.foxinmy.weixin4j.util.ConfigUtil; public class PayTest { private final static Pay2Api PAY2; @@ -31,7 +32,8 @@ public class PayTest { static { ACCOUNT2 = new WeixinPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret", "请填入v3版本的paysignkey", "请填入v2版本的partnerId", "请填入v2版本的partnerKey"); - PAY2 = new Pay2Api(ACCOUNT2, new FileTokenStorager()); + PAY2 = new Pay2Api(ACCOUNT2, new FileTokenStorager(ConfigUtil.getValue( + "token_path", "/tmp/weixin4j/token"))); ACCOUNT3 = new WeixinPayAccount("请填入v3版本的appid", "请填入v3版本的appSecret", "请填入v3版本的paysignkey", "请填入v3版本的mchid"); PAY3 = new WeixinPayProxy(ACCOUNT3); diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java index 6a117234..8fe751ce 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/TokenTest.java @@ -28,7 +28,8 @@ public class TokenTest { WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); tokenHolder = new TokenHolder(new WeixinTokenCreator( weixinAccount.getId(), weixinAccount.getSecret()), - new FileTokenStorager()); + new FileTokenStorager(ConfigUtil.getValue( + "token_path", "/tmp/weixin4j/token"))); } @Test diff --git a/weixin4j-qy/CHANGE.md b/weixin4j-qy/CHANGE.md index a7068f15..e938ab3e 100644 --- a/weixin4j-qy/CHANGE.md +++ b/weixin4j-qy/CHANGE.md @@ -68,4 +68,8 @@ * 2015-06-26 - + 管理成员新增头像参数 \ No newline at end of file + + 管理成员新增头像参数 + +* 2015-07-04 + + + 新增[媒体素材接口](src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java) \ No newline at end of file diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java index c9fb6bb1..cdcd0df0 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java @@ -9,6 +9,9 @@ import com.alibaba.fastjson.JSONObject; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.model.Button; +import com.foxinmy.weixin4j.model.MediaCounter; +import com.foxinmy.weixin4j.model.MediaItem; +import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.qy.api.AgentApi; import com.foxinmy.weixin4j.qy.api.BatchApi; import com.foxinmy.weixin4j.qy.api.HelperApi; @@ -34,6 +37,7 @@ import com.foxinmy.weixin4j.qy.type.InviteType; import com.foxinmy.weixin4j.qy.type.UserStatus; import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenStorager; +import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.type.MediaType; /** @@ -204,75 +208,203 @@ public class WeixinProxy { /** * 上传媒体文件 * + * @param agentid + * 企业应用ID(大于0时视为上传永久媒体文件) * @param file - * 媒体对象 + * 文件对象 * @return 上传到微信服务器返回的媒体标识 * @see com.foxinmy.weixin4j.qy.api.MediaApi - * @see {@link com.foxinmy.weixin4j.qy.WeixinProxy.MediaApi#uploadMedia(InputStream, MediaType)} + * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#uploadMedia(int,InputStream, MediaType)} * @throws WeixinException * @throws IOException */ - public String uploadMedia(File file) throws WeixinException, IOException { - return mediaApi.uploadMedia(file); + public String uploadMedia(int agentid, File file) throws WeixinException, + IOException { + return mediaApi.uploadMedia(agentid, file); } /** - * 上传媒体文件(完全公开。所有管理员均可调用,media_id可以共享) + * 上传媒体文件 *

* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}, * 否则抛出异常. *

* + * @param agentid + * 企业应用ID(大于0时视为上传永久媒体文件) * @param is * 媒体数据流 * @param mediaType * 媒体类型 - * @see com.foxinmy.weixin4j.qy.api.MediaApi - * @see com.foxinmy.weixin4j.type.MediaType * @return 上传到微信服务器返回的媒体标识 - * @see 上传媒体文件说明 - * @throws WeixinException - */ - public String uploadMedia(InputStream is, MediaType mediaType) - throws WeixinException { - return mediaApi.uploadMedia(is, mediaType); - } - - /** - * 下载媒体文件(完全公开。所有管理员均可调用,media_id可以共享) - * - * @param mediaId - * 媒体ID - * @return 二进制数据包 * @see com.foxinmy.weixin4j.qy.api.MediaApi * @see 获取媒体说明 + * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%B4%E6%97%B6%E7%B4%A0%E6%9D%90%E6%96%87%E4%BB%B6">上传临时素材文件说明 + * @see 上传永久素材文件说明 * @throws WeixinException */ - public byte[] downloadMedia(String mediaId) throws WeixinException { - return mediaApi.downloadMedia(mediaId); + public String uploadMedia(int agentid, InputStream is, MediaType mediaType) + throws WeixinException { + return mediaApi.uploadMedia(agentid, is, mediaType); } /** - * 下载媒体文件(完全公开。所有管理员均可调用,media_id可以共享) - *

- * 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常. - *

+ * 下载媒体文件 * + * @param agentid + * 企业应用Id(大于0时视为获取永久媒体文件) * @param mediaId * 存储在微信服务器上的媒体标识 * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @throws WeixinException - * @throws IOException + * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @see com.foxinmy.weixin4j.type.MediaType + * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#downloadMedia(int,String)} + */ + public File downloadMediaFile(int agentid, String mediaId) + throws WeixinException { + return mediaApi.downloadMediaFile(agentid, mediaId); + } + + /** + * 下载媒体文件 + * + * @param agentid + * 企业应用Id(大于0时视为获取永久媒体文件) + * @param mediaId + * 媒体ID + * @return 二进制数据包(需自行判断类型) * @see com.foxinmy.weixin4j.qy.api.MediaApi * @see 获取媒体说明 - * @see com.foxinmy.weixin4j.type.MediaType - * @see {@link com.foxinmy.weixin4j.WeixinProxy.MediaApi#downloadMedia(String)} + * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E4%B8%B4%E6%97%B6%E7%B4%A0%E6%9D%90%E6%96%87%E4%BB%B6">获取临时媒体说明 + * @see 获取永久媒体说明 + * @throws WeixinException */ - public File downloadMediaFile(String mediaId) throws WeixinException { - return mediaApi.downloadMediaFile(mediaId); + public byte[] downloadMedia(int agentid, String mediaId) + throws WeixinException { + return mediaApi.downloadMedia(agentid, mediaId); + } + + /** + * 上传永久图文素材 + *

+ * 、新增的永久素材也可以在公众平台官网素材管理模块中看到,永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000, + * 其他类型为1000 + *

+ * + * @param agentid + * 企业应用的id + * @param articles + * 图文列表 + * @return 上传到微信服务器返回的媒体标识 + * @throws WeixinException + * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @see 上传永久媒体素材 + * @see com.foxinmy.weixin4j.tuple.MpArticle + */ + public String uploadMaterialArticle(int agentid, List articles) + throws WeixinException { + return mediaApi.uploadMaterialArticle(agentid, articles); + } + + /** + * 删除永久媒体素材 + * + * @param agentid + * 企业应用ID + * @param mediaId + * 媒体素材的media_id + * @return 处理结果 + * @throws WeixinException + * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @see 删除永久媒体素材 + */ + public JsonResult deleteMaterialMedia(int agentid, String mediaId) + throws WeixinException { + return mediaApi.deleteMaterialMedia(agentid, mediaId); + } + + /** + * 修改永久图文素材 + * + * @param agentid + * 企业应用的id + * @param mediaId + * 上传后的media_id + * @param articles + * 图文列表 + * @return 操作结果 + * @throws WeixinException + * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @see 修改永久媒体素材 + * @see com.foxinmy.weixin4j.tuple.MpArticle + */ + public String updateMaterialArticle(int agentid, String mediaId, + List articles) throws WeixinException { + return mediaApi.updateMaterialArticle(agentid, mediaId, articles); + } + + /** + * 获取永久媒体素材的总数 + * + * @param agentid + * 企业应用id + * @return 总数对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @see com.foxinmy.weixin4j.model.MediaCounter + * @see 获取素材总数 + */ + public MediaCounter countMaterialMedia(int agentid) throws WeixinException { + return mediaApi.countMaterialMedia(agentid); + } + + /** + * 获取媒体素材记录列表 + * + * @param agentid + * 企业应用ID + * @param mediaType + * 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news)、文件(file) + * @param offset + * 从全部素材的该偏移位置开始返回,0表示从第一个素材返回 + * @param count + * 返回素材的数量,取值在1到20之间 + * @return 媒体素材的记录对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @see com.foxinmy.weixin4j.model.MediaRecord + * @see com.foxinmy.weixin4j.type.MediaType + * @see com.foxinmy.weixin4j.model.MediaItem + * @see 获取素材列表 + */ + public MediaRecord listMaterialMedia(int agentid, MediaType mediaType, + int offset, int count) throws WeixinException { + return mediaApi.listMaterialMedia(agentid, mediaType, offset, count); + } + + /** + * 获取全部的媒体素材 + * + * @param agentid + * 企业应用id + * @param mediaType + * 媒体类型 + * @return 素材列表 + * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#listMaterialMedia(int,MediaType, int, int)} + * @throws WeixinException + */ + public List listAllMaterialMedia(int agentid, MediaType mediaType) + throws WeixinException { + return mediaApi.listAllMaterialMedia(agentid, mediaType); } /** diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java index b3074429..9ec6aaec 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java @@ -8,6 +8,7 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; +import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -17,21 +18,28 @@ import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.serializer.PropertyFilter; import com.foxinmy.weixin4j.exception.WeixinException; +import com.foxinmy.weixin4j.http.HttpGet; import com.foxinmy.weixin4j.http.apache.FormBodyPart; import com.foxinmy.weixin4j.http.apache.InputStreamBody; +import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Consts; +import com.foxinmy.weixin4j.model.MediaCounter; +import com.foxinmy.weixin4j.model.MediaItem; +import com.foxinmy.weixin4j.model.MediaRecord; import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.qy.model.Callback; import com.foxinmy.weixin4j.qy.model.Party; import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.token.TokenHolder; +import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.FileUtil; import com.foxinmy.weixin4j.util.IOUtil; import com.foxinmy.weixin4j.util.ObjectId; import com.foxinmy.weixin4j.util.StringUtil; +import com.foxinmy.weixin4j.util.Weixin4jConst; /** * 媒体相关API @@ -41,7 +49,7 @@ import com.foxinmy.weixin4j.util.StringUtil; * @date 2014年9月25日 * @since JDK 1.7 * @see 管理多媒体文件 + * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E7%B4%A0%E6%9D%90%E6%96%87%E4%BB%B6">管理素材文件 * @see com.foxinmy.weixin4j.type.MediaType */ public class MediaApi extends QyApi { @@ -55,96 +63,118 @@ public class MediaApi extends QyApi { /** * 上传媒体文件 * + * @param agentid + * 企业应用ID(大于0时视为上传永久媒体文件) * @param file - * 媒体对象 + * 文件对象 * @return 上传到微信服务器返回的媒体标识 - * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#uploadMedia(InputStream, MediaType)} + * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#uploadMedia(int,InputStream, MediaType)} * @throws WeixinException * @throws IOException */ - public String uploadMedia(File file) throws WeixinException, IOException { + public String uploadMedia(int agentid, File file) throws WeixinException, + IOException { String mediaTypeKey = IOUtil.getExtension(file.getName()); if (StringUtil.isBlank(mediaTypeKey)) { mediaTypeKey = FileUtil.getFileType(file); } MediaType mediaType = null; - if (mediaTypeKey.equals("jpg")) { + if ("bmp/png/jpeg/jpg/gif".contains(mediaTypeKey)) { mediaType = MediaType.image; - } else if ("amr/mp3".contains(mediaTypeKey)) { + } else if ("mp3/wma/wav/amr".contains(mediaTypeKey)) { mediaType = MediaType.voice; - } else if (mediaTypeKey.equals("mp4")) { + } else if ("mp4".equals(mediaTypeKey)) { mediaType = MediaType.video; } else { mediaType = MediaType.file; } - return uploadMedia(new FileInputStream(file), mediaType); + return uploadMedia(agentid, new FileInputStream(file), mediaType); } /** - * 上传媒体文件(完全公开。所有管理员均可调用,media_id可以共享) + * 上传媒体文件 *

* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}, * 否则抛出异常. *

* + * @param agentid + * 企业应用ID(大于0时视为上传永久媒体文件) * @param is * 媒体数据流 * @param mediaType * 媒体类型 * @return 上传到微信服务器返回的媒体标识 * @see 上传媒体文件说明 + * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E4%B8%B4%E6%97%B6%E7%B4%A0%E6%9D%90%E6%96%87%E4%BB%B6">上传临时素材文件说明 + * @see 上传永久素材文件说明 * @throws WeixinException */ - public String uploadMedia(InputStream is, MediaType mediaType) + public String uploadMedia(int agentid, InputStream is, MediaType mediaType) throws WeixinException { - String file_upload_uri = getRequestUri("file_upload_uri"); Token token = tokenHolder.getToken(); - if (mediaType == null || mediaType == MediaType.news) { + if (mediaType == null) { mediaType = MediaType.file; } else if (mediaType == MediaType.thumb) { mediaType = MediaType.image; + } else if (mediaType == MediaType.news) { + throw new WeixinException( + "please invoke uploadMaterialArticle method"); } - WeixinResponse response = weixinClient.post(String.format( - file_upload_uri, token.getAccessToken(), mediaType), - new FormBodyPart("media", new InputStreamBody(is, mediaType - .getContentType().getMimeType(), ObjectId.get() - .toHexString()))); try { - is.close(); - } catch (IOException e) { - ; + WeixinResponse response = null; + if (agentid > 0) { + String material_media_upload_uri = getRequestUri("material_media_upload_uri"); + response = weixinClient.post(String.format( + material_media_upload_uri, token.getAccessToken(), + mediaType.name(), agentid), new FormBodyPart("media", + new InputStreamBody(is, mediaType.getContentType() + .getMimeType(), ObjectId.get().toHexString()))); + } else { + String file_upload_uri = getRequestUri("file_upload_uri"); + response = weixinClient.post(String.format(file_upload_uri, + token.getAccessToken(), mediaType.name()), + new FormBodyPart("media", new InputStreamBody(is, + mediaType.getContentType().getMimeType(), + ObjectId.get().toHexString()))); + } + return response.getAsJson().getString("media_id"); + } finally { + if (is != null) { + try { + is.close(); + } catch (IOException e) { + ; + } + } } - return response.getAsJson().getString("media_id"); } /** - * 下载媒体文件(完全公开。所有管理员均可调用,media_id可以共享) - *

- * 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常. - *

+ * 下载媒体文件 * + * @param agentid + * 企业应用Id(大于0时视为获取永久媒体文件) * @param mediaId * 存储在微信服务器上的媒体标识 * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @throws WeixinException - * @throws IOException - * @see 获取媒体说明 * @see com.foxinmy.weixin4j.type.MediaType - * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#downloadMedia(String)} + * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#downloadMedia(int,String)} */ - public File downloadMediaFile(String mediaId) throws WeixinException { - String media_path = ConfigUtil.getValue("media_path"); + public File downloadMediaFile(int agentid, String mediaId) + throws WeixinException { + String media_path = ConfigUtil.getValue("media_path", + Weixin4jConst.DEFAULT_MEDIA_PATH); File file = new File(media_path + File.separator + mediaId); if (file.exists()) { return file; } - byte[] datas = downloadMedia(mediaId); + byte[] datas = downloadMedia(agentid, mediaId); OutputStream os = null; try { - boolean flag = file.createNewFile(); - if (flag) { + if (file.createNewFile()) { os = new FileOutputStream(file); os.write(datas); } else { @@ -166,21 +196,216 @@ public class MediaApi extends QyApi { } /** - * 下载媒体文件(完全公开。所有管理员均可调用,media_id可以共享) + * 下载媒体文件 * + * @param agentid + * 企业应用Id(大于0时视为获取永久媒体文件) * @param mediaId * 媒体ID - * @return 二进制数据包 + * @return 二进制数据包(需自行判断类型) * @see 获取媒体说明 + * href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E4%B8%B4%E6%97%B6%E7%B4%A0%E6%9D%90%E6%96%87%E4%BB%B6">获取临时媒体说明 + * @see 获取永久媒体说明 * @throws WeixinException */ - public byte[] downloadMedia(String mediaId) throws WeixinException { + public byte[] downloadMedia(int agentid, String mediaId) + throws WeixinException { Token token = tokenHolder.getToken(); - String file_download_uri = getRequestUri("file_download_uri"); + try { + HttpGet method = null; + if (agentid > 0) { + String material_media_download_uri = getRequestUri("material_media_download_uri"); + method = new HttpGet(String.format(material_media_download_uri, + token.getAccessToken(), mediaId, agentid)); + } else { + String meida_download_uri = getRequestUri("meida_download_uri"); + method = new HttpGet(String.format(meida_download_uri, + token.getAccessToken(), mediaId)); + } + return weixinClient.execute(method).getContent(); + } catch (IOException e) { + throw new WeixinException(e); + } + } + + /** + * 上传永久图文素材 + *

+ * 、新增的永久素材也可以在公众平台官网素材管理模块中看到,永久素材的数量是有上限的,请谨慎新增。图文消息素材和图片素材的上限为5000, + * 其他类型为1000 + *

+ * + * @param agentid + * 企业应用的id + * @param articles + * 图文列表 + * @return 上传到微信服务器返回的媒体标识 + * @throws WeixinException + * @see 上传永久媒体素材 + * @see com.foxinmy.weixin4j.tuple.MpArticle + */ + public String uploadMaterialArticle(int agentid, List articles) + throws WeixinException { + Token token = tokenHolder.getToken(); + String material_article_upload_uri = getRequestUri("material_article_upload_uri"); + JSONObject obj = new JSONObject(); + obj.put("agentid", agentid); + JSONObject news = new JSONObject(); + news.put("articles", articles); + obj.put("mpnews", news); + WeixinResponse response = weixinClient.post( + String.format(material_article_upload_uri, + token.getAccessToken()), obj.toJSONString()); + + return response.getAsJson().getString("media_id"); + } + + /** + * 删除永久媒体素材 + * + * @param agentid + * 企业应用ID + * @param mediaId + * 媒体素材的media_id + * @return 处理结果 + * @throws WeixinException + * @see 删除永久媒体素材 + */ + public JsonResult deleteMaterialMedia(int agentid, String mediaId) + throws WeixinException { + Token token = tokenHolder.getToken(); + String material_media_del_uri = getRequestUri("material_media_del_uri"); WeixinResponse response = weixinClient.get(String.format( - file_download_uri, token.getAccessToken(), mediaId)); - return response.getContent(); + material_media_del_uri, token.getAccessToken(), mediaId, + agentid)); + return response.getAsJsonResult(); + } + + /** + * 修改永久图文素材 + * + * @param agentid + * 企业应用的id + * @param mediaId + * 上传后的media_id + * @param articles + * 图文列表 + * @return 操作结果 + * @throws WeixinException + * @see 修改永久媒体素材 + * @see com.foxinmy.weixin4j.tuple.MpArticle + */ + public String updateMaterialArticle(int agentid, String mediaId, + List articles) throws WeixinException { + Token token = tokenHolder.getToken(); + String material_article_update_uri = getRequestUri("material_article_update_uri"); + JSONObject obj = new JSONObject(); + obj.put("agentid", agentid); + JSONObject news = new JSONObject(); + news.put("articles", articles); + obj.put("mpnews", news); + obj.put("media_id", mediaId); + WeixinResponse response = weixinClient.post( + String.format(material_article_update_uri, + token.getAccessToken()), obj.toJSONString()); + + return response.getAsJson().getString("media_id"); + } + + /** + * 获取永久媒体素材的总数 + * + * @param agentid + * 企业应用id + * @return 总数对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.model.MediaCounter + * @see 获取素材总数 + */ + public MediaCounter countMaterialMedia(int agentid) throws WeixinException { + Token token = tokenHolder.getToken(); + String material_media_count_uri = getRequestUri("material_media_count_uri"); + WeixinResponse response = weixinClient.get(String.format( + material_media_count_uri, token.getAccessToken(), agentid)); + JSONObject result = response.getAsJson(); + MediaCounter counter = JSON.toJavaObject(result, MediaCounter.class); + counter.setNewsCount(result.getIntValue("mpnews_count")); + return counter; + } + + /** + * 获取媒体素材记录列表 + * + * @param agentid + * 企业应用ID + * @param mediaType + * 素材的类型,图片(image)、视频(video)、语音 (voice)、图文(news)、文件(file) + * @param offset + * 从全部素材的该偏移位置开始返回,0表示从第一个素材返回 + * @param count + * 返回素材的数量,取值在1到20之间 + * @return 媒体素材的记录对象 + * @throws WeixinException + * @see com.foxinmy.weixin4j.model.MediaRecord + * @see com.foxinmy.weixin4j.type.MediaType + * @see com.foxinmy.weixin4j.model.MediaItem + * @see 获取素材列表 + */ + public MediaRecord listMaterialMedia(int agentid, MediaType mediaType, + int offset, int count) throws WeixinException { + Token token = tokenHolder.getToken(); + String material_media_list_uri = getRequestUri("material_media_list_uri"); + JSONObject obj = new JSONObject(); + obj.put("type", + mediaType == MediaType.news ? "mpnews" : mediaType.name()); + obj.put("offset", offset); + obj.put("count", count); + WeixinResponse response = weixinClient.post( + String.format(material_media_list_uri, token.getAccessToken()), + obj.toJSONString()); + obj = response.getAsJson(); + + MediaRecord mediaRecord = JSON.toJavaObject(obj, MediaRecord.class); + if (mediaType == MediaType.news) { + mediaRecord.setItems(JSON.parseArray(obj.getString("itemlist"), + MediaItem.class)); + } + mediaRecord.setMediaType(mediaType); + return mediaRecord; + } + + /** + * 获取全部的媒体素材 + * + * @param agentid + * 企业应用id + * @param mediaType + * 媒体类型 + * @return 素材列表 + * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#listMaterialMedia(int,MediaType, int, int)} + * @throws WeixinException + */ + public List listAllMaterialMedia(int agentid, MediaType mediaType) + throws WeixinException { + int offset = 0; + int count = 20; + List mediaList = new ArrayList(); + MediaRecord mediaRecord = null; + for (;;) { + mediaRecord = listMaterialMedia(agentid, mediaType, offset, count); + mediaList.addAll(mediaRecord.getItems()); + if (offset >= mediaRecord.getTotalCount()) { + break; + } + offset += count; + } + return mediaList; } /** @@ -217,35 +442,39 @@ public class MediaApi extends QyApi { private String batchUpload(String batchName, List models) throws WeixinException { - JSONObject csvObj = JSON.parseObject(getConfigValue(batchName)); - JSONArray columns = csvObj.getJSONArray("column"); StringWriter writer = new StringWriter(); - writer.write(csvObj.getString("header")); - final Map column = new LinkedHashMap(); - for (Object col : columns) { - column.put(col.toString(), ""); - } - writer.write("\r\n"); - for (T model : models) { - JSON.toJSONString(model, new PropertyFilter() { - @Override - public boolean apply(Object object, String name, Object value) { - if (column.containsKey(name)) { - column.put(name, value); - } - return true; - } - }); - writer.write(StringUtil.join(column.values(), ',')); - writer.write("\r\n"); - } - String mediaId = uploadMedia(new ByteArrayInputStream(writer - .getBuffer().toString().getBytes(Consts.UTF_8)), MediaType.file); try { - writer.close(); - } catch (IOException e) { - ; + JSONObject csvObj = JSON.parseObject(weixinBundle().getString( + batchName)); + JSONArray columns = csvObj.getJSONArray("column"); + writer.write(csvObj.getString("header")); + final Map column = new LinkedHashMap(); + for (Object col : columns) { + column.put(col.toString(), ""); + } + writer.write("\r\n"); + for (T model : models) { + JSON.toJSONString(model, new PropertyFilter() { + @Override + public boolean apply(Object object, String name, + Object value) { + if (column.containsKey(name)) { + column.put(name, value); + } + return true; + } + }); + writer.write(StringUtil.join(column.values(), ',')); + writer.write("\r\n"); + } + return uploadMedia(0, new ByteArrayInputStream(writer.getBuffer() + .toString().getBytes(Consts.UTF_8)), MediaType.file); + } finally { + try { + writer.close(); + } catch (IOException e) { + ; + } } - return mediaId; } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java index 03d95403..8b9e9f18 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/QyApi.java @@ -33,7 +33,7 @@ public class QyApi extends BaseApi { } @Override - protected String getConfigValue(String key) { - return WEIXIN_BUNDLE.getString(key); + protected ResourceBundle weixinBundle() { + return WEIXIN_BUNDLE; } } diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/UserApi.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/UserApi.java index 9c6fd3cd..1772563e 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/UserApi.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/UserApi.java @@ -119,7 +119,7 @@ public class UserApi extends QyApi { } if (avatar != null) { obj.put("avatar_mediaid", - mediaApi.uploadMedia(avatar, MediaType.image)); + mediaApi.uploadMedia(0, avatar, MediaType.image)); } Token token = tokenHolder.getToken(); WeixinResponse response = weixinClient.post( diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties index 47092838..d847d32f 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/weixin.properties @@ -99,4 +99,23 @@ suite_set_agent_uri={api_base_url}/service/set_agent?suite_access_token=%s # userid\u8f6c\u6362\u6210openid userid2openid_uri={api_base_url}/user/convert_to_openid?access_token=%s # openid\u8f6c\u6362\u6210userid -openid2userid_uri={api_base_url}/user/convert_to_userid?access_token=%s \ No newline at end of file +openid2userid_uri={api_base_url}/user/convert_to_userid?access_token=%s + +# \u4e0a\u4f20\u4e34\u65f6\u7d20\u6750\u6587\u4ef6 +media_upload_uri={api_base_url}/media/upload?access_token=%s&type=%s +# \u4e0b\u8f7d\u4e34\u65f6\u7d20\u6750\u6587\u4ef6 +meida_download_uri={api_base_url}/media/get?access_token=%s&media_id=%s +# \u4e0a\u4f20\u6c38\u4e45\u56fe\u6587\u7d20\u6750 +material_article_upload_uri={api_base_url}/material/add_news?access_token=%s +# \u4e0a\u4f20\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +material_media_upload_uri={api_base_url}/material/add_material?access_token=%s&type=%s&agentid=%d +# \u4e0b\u8f7d\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +material_media_download_uri={api_base_url}/material/get?access_token=%s&media_id=%s&agentid=%d +# \u66f4\u65b0\u6c38\u4e45\u56fe\u6587\u7d20\u6750 +material_article_update_uri={api_base_url}/material/update_mpnews?access_token=%s +# \u5220\u9664\u6c38\u4e45\u5a92\u4f53\u7d20\u6750 +material_media_del_uri={api_base_url}/material/del?access_token=%s&media_id=%s&agentid=%d +# \u83b7\u53d6\u5a92\u4f53\u7d20\u6750\u603b\u6570 +material_media_count_uri={api_base_url}/material/get_count?access_token=%s&agentid=%d +# \u83b7\u53d6\u5a92\u4f53\u7d20\u6750\u5217\u8868 +material_media_list_uri={api_base_url}/material/batchget?access_token=%s \ No newline at end of file diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/User.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/User.java index e1e0685e..68d1d6e1 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/User.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/model/User.java @@ -70,7 +70,7 @@ public class User implements Serializable { /** * 启用/禁用成员。1表示启用成员,0表示禁用成员 */ - private int enable; + private Integer enable; /** * 非必须 扩展属性。扩展属性需要在WEB管理端创建后才生效,否则忽略未知属性的赋值 */ @@ -218,16 +218,23 @@ public class User implements Serializable { this.status = status; } - public int getEnable() { + public int getStatus() { + return status; + } + + public Integer getEnable() { return enable; } @JSONField(serialize = false, deserialize = false) public boolean getFormatEnable() { - return enable == 1; + if (enable != null) { + return enable.intValue() == 1; + } + return false; } - public void setEnable(int enable) { + public void setEnable(Integer enable) { this.enable = enable; } diff --git a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/MediaTest.java b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/MediaTest.java index e7f3159d..1753704b 100644 --- a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/MediaTest.java +++ b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/MediaTest.java @@ -9,6 +9,7 @@ import org.junit.Test; import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.qy.api.MediaApi; +import com.foxinmy.weixin4j.type.MediaType; /** * 媒体上传下载测试 @@ -30,8 +31,8 @@ public class MediaTest extends TokenTest { @Test public void upload() throws IOException, WeixinException { - File file = new File("/tmp/test.docx"); - String mediaId = mediaApi.uploadMedia(file); + File file = new File("//Users/jy/Downloads/import_file.csv"); + String mediaId = mediaApi.uploadMedia(1, file); // 1-1gpykXsR8bhNvO13-ZvskptCBxQF1UE535jFdCF63N2inGRAqEb-psF6eppjIIl // 1CF6sBgWWFGY9s4JCEet5ASszsTuyHpeN1f2LWXADveqBlKoxSgb3cO401NEM7dNY Assert.assertNotNull(mediaId); @@ -41,7 +42,13 @@ public class MediaTest extends TokenTest { @Test public void download() throws WeixinException, IOException { File file = mediaApi - .downloadMediaFile("1CF6sBgWWFGY9s4JCEet5ASszsTuyHpeN1f2LWXADveqBlKoxSgb3cO401NEM7dNY"); + .downloadMediaFile(1, + "jM5OWhnYb2DgrNm97HGj8aUdsZcweQc93tnwbH1mERo"); Assert.assertTrue(file.exists()); } + + @Test + public void listAll() throws WeixinException { + mediaApi.listAllMaterialMedia(1, MediaType.image); + } } \ No newline at end of file diff --git a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java index 3f2f573a..d62e7d2f 100644 --- a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java +++ b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/TokenTest.java @@ -28,7 +28,8 @@ public class TokenTest { WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); tokenHolder = new TokenHolder(new WeixinTokenCreator( weixinAccount.getId(), weixinAccount.getSecret()), - new FileTokenStorager()); + new FileTokenStorager(ConfigUtil.getValue( + "token_path", "/tmp/weixin4j/token"))); } @Test diff --git a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/UserTest.java b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/UserTest.java index 86645977..e5437666 100644 --- a/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/UserTest.java +++ b/weixin4j-qy/src/test/java/com/foxinmy/weixin4j/qy/test/UserTest.java @@ -71,10 +71,7 @@ public class UserTest extends TokenTest { @Test public void list() throws WeixinException { - List userList = userApi.listUser(1, true, UserStatus.BOTH, true); - Assert.assertFalse(userList.isEmpty()); - System.out.println(userList); - userList = userApi.listUser(1); + List userList = userApi.listUser(3, true, UserStatus.BOTH, true); Assert.assertFalse(userList.isEmpty()); System.out.println(userList); } diff --git a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java index cdfcf03f..156a07b6 100644 --- a/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java +++ b/weixin4j-server/src/main/java/com/foxinmy/weixin4j/startup/WeixinServerBootstrap.java @@ -56,7 +56,7 @@ public final class WeixinServerBootstrap { /** * 服务启动的默认端口 */ - public final static int DEFAULT_SERVERPORT = 80; + public final static int DEFAULT_SERVERPORT = 30000; /** * 消息分发器 */