weixin4j-qy:新增媒体素材接口

This commit is contained in:
jinyu 2015-07-04 18:28:24 +08:00
parent 402d87c978
commit 82cc589640
33 changed files with 820 additions and 282 deletions

View File

@ -362,3 +362,7 @@
* 2015-06-27 * 2015-06-27
+ 媒体接口(MediaApi)中上传方法中的File类型调整为InputStream + 媒体接口(MediaApi)中上传方法中的File类型调整为InputStream
* 2015-07-04
+ **weixin4j-qy**: 新增[媒体素材接口](weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java)

View File

@ -1,14 +1,16 @@
package com.foxinmy.weixin4j.api; package com.foxinmy.weixin4j.api;
import java.util.MissingResourceException;
import java.util.ResourceBundle;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import com.alibaba.fastjson.JSON;
import com.foxinmy.weixin4j.http.weixin.WeixinHttpClient; import com.foxinmy.weixin4j.http.weixin.WeixinHttpClient;
import com.foxinmy.weixin4j.model.WeixinAccount; import com.foxinmy.weixin4j.model.WeixinAccount;
import com.foxinmy.weixin4j.token.FileTokenStorager; import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
/** /**
* API基础 * API基础
@ -22,12 +24,16 @@ import com.foxinmy.weixin4j.util.ConfigUtil;
*/ */
public abstract class BaseApi { 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) { protected String getRequestUri(String key) {
String url = getConfigValue(key); String url = weixinBundle().getString(key);
Pattern p = Pattern.compile("(\\{[^\\}]*\\})"); Pattern p = Pattern.compile("(\\{[^\\}]*\\})");
Matcher m = p.matcher(url); Matcher m = p.matcher(url);
StringBuffer sb = new StringBuffer(); StringBuffer sb = new StringBuffer();
@ -44,16 +50,22 @@ public abstract class BaseApi {
/** /**
* 默认使用weixin4j.properties文件中的公众号信息 * 默认使用weixin4j.properties文件中的公众号信息
*/ */
public final static WeixinAccount DEFAULT_WEIXIN_ACCOUNT; public static WeixinAccount DEFAULT_WEIXIN_ACCOUNT;
/** /**
* 默认token使用File的方式存储 * 默认token使用File的方式存储
*/ */
public final static TokenStorager DEFAULT_TOKEN_STORAGER; public static TokenStorager DEFAULT_TOKEN_STORAGER;
static { static {
DEFAULT_WEIXIN_ACCOUNT = JSON.parseObject( try {
ConfigUtil.getValue("account"), WeixinAccount.class); DEFAULT_WEIXIN_ACCOUNT = ConfigUtil.getWeixinAccount();
DEFAULT_TOKEN_STORAGER = new FileTokenStorager(); } 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));
} }
} }

View File

@ -128,10 +128,14 @@ public class SimpleHttpClient implements HttpClient {
httpEntity = ((HttpEntityRequest) request).getEntity(); httpEntity = ((HttpEntityRequest) request).getEntity();
connection.setUseCaches(false); connection.setUseCaches(false);
if (httpEntity != null) { if (httpEntity != null) {
connection.setFixedLengthStreamingMode(httpEntity if (httpEntity.getContentLength() > 0l) {
.getContentLength()); connection.setFixedLengthStreamingMode(httpEntity
connection.setRequestProperty("Content-Type", httpEntity .getContentLength());
.getContentType().getMimeType()); }
if (httpEntity.getContentType() != null) {
connection.setRequestProperty("Content-Type", httpEntity
.getContentType().getMimeType());
}
} }
} }
connection.connect(); connection.connect();

View File

@ -37,56 +37,62 @@ import java.io.OutputStream;
*/ */
public class InputStreamBody extends AbstractContentBody { public class InputStreamBody extends AbstractContentBody {
private final InputStream in; private final InputStream in;
private final String filename; private final String filename;
public InputStreamBody(final InputStream in, final String mimeType, final String filename) { public InputStreamBody(final InputStream in, final String mimeType,
super(mimeType); final String filename) {
if (in == null) { super(mimeType);
throw new IllegalArgumentException("Input stream may not be null"); if (in == null) {
} throw new IllegalArgumentException("Input stream may not be null");
this.in = in; }
this.filename = filename; this.in = in;
} this.filename = filename;
}
public InputStreamBody(final InputStream in, final String filename) { public InputStreamBody(final InputStream in, final String filename) {
this(in, "application/octet-stream", filename); this(in, "application/octet-stream", filename);
} }
public InputStream getInputStream() { public InputStream getInputStream() {
return this.in; return this.in;
} }
public void writeTo(final OutputStream out) throws IOException { public void writeTo(final OutputStream out) throws IOException {
if (out == null) { if (out == null) {
throw new IllegalArgumentException("Output stream may not be null"); throw new IllegalArgumentException("Output stream may not be null");
} }
try { try {
byte[] tmp = new byte[4096]; byte[] tmp = new byte[4096];
int l; int l;
while ((l = this.in.read(tmp)) != -1) { while ((l = this.in.read(tmp)) != -1) {
out.write(tmp, 0, l); out.write(tmp, 0, l);
} }
out.flush(); out.flush();
} finally { } finally {
this.in.close(); this.in.close();
} }
} }
public String getTransferEncoding() { public String getTransferEncoding() {
return MIME.ENC_BINARY; return MIME.ENC_BINARY;
} }
public String getCharset() { public String getCharset() {
return null; return null;
} }
public long getContentLength() { public long getContentLength() {
return -1; try {
} return in.available();
} catch (IOException e) {
;
}
return -1;
}
public String getFilename() { public String getFilename() {
return this.filename; return this.filename;
} }
} }

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.model; package com.foxinmy.weixin4j.model;
import java.io.Serializable; import java.io.Serializable;
@ -17,6 +17,16 @@ public class MediaCounter implements Serializable {
private static final long serialVersionUID = -1752502821323552783L; 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; 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 @Override
public String toString() { public String toString() {
return "MediaCounter [voiceCount=" + voiceCount + ", videoCount=" return "MediaCounter [totalCount=" + totalCount + ", fileCount="
+ fileCount + ", voiceCount=" + voiceCount + ", videoCount="
+ videoCount + ", imageCount=" + imageCount + ", newsCount=" + videoCount + ", imageCount=" + imageCount + ", newsCount="
+ newsCount + "]"; + newsCount + "]";
} }

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.model; package com.foxinmy.weixin4j.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.Date; import java.util.Date;
@ -37,7 +37,7 @@ public class MediaItem implements Serializable {
/** /**
* 图文素材列表 * 图文素材列表
*/ */
@JSONField(name = "news_item") @JSONField(name = "articles")
private List<MpArticle> articles; private List<MpArticle> articles;
public String getMediaId() { public String getMediaId() {

View File

@ -1,4 +1,4 @@
package com.foxinmy.weixin4j.mp.model; package com.foxinmy.weixin4j.model;
import java.io.Serializable; import java.io.Serializable;
import java.util.List; import java.util.List;

View File

@ -26,6 +26,7 @@ import com.foxinmy.weixin4j.type.BillType;
import com.foxinmy.weixin4j.type.CurrencyType; import com.foxinmy.weixin4j.type.CurrencyType;
import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdQuery;
import com.foxinmy.weixin4j.util.ConfigUtil; 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.pay3Api = new Pay3Api(weixinAccount);
this.couponApi = new CouponApi(weixinAccount); this.couponApi = new CouponApi(weixinAccount);
this.cashApi = new CashApi(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));
} }
/** /**

View File

@ -7,7 +7,6 @@ import java.io.IOException;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.model.Token; import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.xml.XmlStream; import com.foxinmy.weixin4j.xml.XmlStream;
/** /**
@ -22,10 +21,6 @@ public class FileTokenStorager implements TokenStorager {
private final String cachePath; private final String cachePath;
public FileTokenStorager() {
this(ConfigUtil.getValue("token_path"));
}
public FileTokenStorager(String cachePath) { public FileTokenStorager(String cachePath) {
this.cachePath = cachePath; this.cachePath = cachePath;
} }

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.util; package com.foxinmy.weixin4j.util;
import java.io.File; import java.io.File;
import java.util.MissingResourceException;
import java.util.ResourceBundle; import java.util.ResourceBundle;
import java.util.Set; import java.util.Set;
@ -49,6 +50,25 @@ public class ConfigUtil {
return weixinBundle.getString(key); 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:]如果存在则拼接项目路径后返回 一般用于文件的绝对路径获取 * 判断属性是否存在[classpath:]如果存在则拼接项目路径后返回 一般用于文件的绝对路径获取
* *
@ -60,6 +80,24 @@ public class ConfigUtil {
CLASSPATH_VALUE)).getPath(); 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() { public static WeixinAccount getWeixinAccount() {
String text = getValue("account"); String text = getValue("account");
return JSON.parseObject(text, WeixinAccount.class); return JSON.parseObject(text, WeixinAccount.class);

View File

@ -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";
}

View File

@ -9,6 +9,9 @@ import java.util.List;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.JsonResult;
import com.foxinmy.weixin4j.model.Button; 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.CustomApi;
import com.foxinmy.weixin4j.mp.api.DataApi; import com.foxinmy.weixin4j.mp.api.DataApi;
import com.foxinmy.weixin4j.mp.api.GroupApi; 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.Group;
import com.foxinmy.weixin4j.mp.model.KfAccount; import com.foxinmy.weixin4j.mp.model.KfAccount;
import com.foxinmy.weixin4j.mp.model.KfSession; 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.MenuSetting;
import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.mp.model.SemQuery; import com.foxinmy.weixin4j.mp.model.SemQuery;
@ -134,7 +134,7 @@ public class WeixinProxy {
* 是否永久上传 * 是否永久上传
* @return 上传到微信服务器返回的媒体标识 * @return 上传到微信服务器返回的媒体标识
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#uploadMedia(InputStream, MediaType,boolean)} * @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 WeixinException
* @throws IOException * @throws IOException
*/ */
@ -162,7 +162,7 @@ public class WeixinProxy {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久素材</a> * href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久素材</a>
* @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.type.MediaType
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
* @throws WeixinException * @throws WeixinException
*/ */
public String uploadMedia(InputStream is, MediaType mediaType, public String uploadMedia(InputStream is, MediaType mediaType,
@ -186,7 +186,7 @@ public class WeixinProxy {
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html">上传下载说明</a> * href="http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html">上传下载说明</a>
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
* @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#downloadMedia(String)} * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#downloadMedia(String)}
*/ */
public File downloadMediaFile(String mediaId, boolean isMaterial) public File downloadMediaFile(String mediaId, boolean isMaterial)
@ -203,7 +203,7 @@ public class WeixinProxy {
* 是否永久素材 * 是否永久素材
* @return 二进制数据包 * @return 二进制数据包
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html">上传下载说明</a> * href="http://mp.weixin.qq.com/wiki/10/78b15308b053286e2a66b33f0f0f5fb6.html">上传下载说明</a>
*/ */
@ -223,7 +223,7 @@ public class WeixinProxy {
* 图文列表 * 图文列表
* @return 上传到微信服务器返回的媒体标识 * @return 上传到微信服务器返回的媒体标识
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
* @see com.foxinmy.weixin4j.tuple.MpArticle * @see com.foxinmy.weixin4j.tuple.MpArticle
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久媒体素材</a> * href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久媒体素材</a>
@ -243,7 +243,7 @@ public class WeixinProxy {
* @see <a href= * @see <a href=
* "http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html">下载永久媒体素材</a> * "http://mp.weixin.qq.com/wiki/4/b3546879f07623cb30df9ca0e420a5d0.html">下载永久媒体素材</a>
* @see com.foxinmy.weixin4j.tuple.MpArticle * @see com.foxinmy.weixin4j.tuple.MpArticle
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
*/ */
public List<MpArticle> downloadArticle(String mediaId) public List<MpArticle> downloadArticle(String mediaId)
throws WeixinException { throws WeixinException {
@ -261,7 +261,7 @@ public class WeixinProxy {
* 图文列表 * 图文列表
* @return 处理结果 * @return 处理结果
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
* @see com.foxinmy.weixin4j.tuple.MpArticle * @see com.foxinmy.weixin4j.tuple.MpArticle
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/4/19a59cba020d506e767360ca1be29450.html">更新永久图文素材</a> * href="http://mp.weixin.qq.com/wiki/4/19a59cba020d506e767360ca1be29450.html">更新永久图文素材</a>
@ -278,7 +278,7 @@ public class WeixinProxy {
* 媒体素材的media_id * 媒体素材的media_id
* @return 处理结果 * @return 处理结果
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/5/e66f61c303db51a6c0f90f46b15af5f5.html">删除永久媒体素材</a> * href="http://mp.weixin.qq.com/wiki/5/e66f61c303db51a6c0f90f46b15af5f5.html">删除永久媒体素材</a>
*/ */
@ -290,7 +290,7 @@ public class WeixinProxy {
/** /**
* 上传永久视频素材 * 上传永久视频素材
* *
* @param file * @param is
* 大小不超过1M且格式为MP4的视频文件 * 大小不超过1M且格式为MP4的视频文件
* @param title * @param title
* 视频标题 * 视频标题
@ -299,13 +299,12 @@ public class WeixinProxy {
* @return 上传到微信服务器返回的媒体标识 * @return 上传到微信服务器返回的媒体标识
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久媒体素材</a> * href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久媒体素材</a>
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
* @throws WeixinException * @throws WeixinException
* @throws IOException
*/ */
public String uploadMaterialVideo(File file, String title, public String uploadMaterialVideo(InputStream is, String title,
String introduction) throws WeixinException, IOException { String introduction) throws WeixinException {
return mediaApi.uploadMaterialVideo(file, title, introduction); return mediaApi.uploadMaterialVideo(is, title, introduction);
} }
/** /**
@ -316,7 +315,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.model.MediaCounter * @see com.foxinmy.weixin4j.mp.model.MediaCounter
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html">获取素材总数</a> * href="http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html">获取素材总数</a>
* @see com.foxinmy.weixin4j.mp.api.MediaApi * @see com.com.foxinmy.weixin4j.mp.api.MediaApi
*/ */
public MediaCounter countMaterialMedia() throws WeixinException { public MediaCounter countMaterialMedia() throws WeixinException {
return mediaApi.countMaterialMedia(); return mediaApi.countMaterialMedia();
@ -333,7 +332,7 @@ public class WeixinProxy {
* 返回素材的数量取值在1到20之间 * 返回素材的数量取值在1到20之间
* @return 媒体素材的记录对象 * @return 媒体素材的记录对象
* @throws WeixinException * @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.mp.model.MediaRecord
* @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.type.MediaType
* @see com.foxinmy.weixin4j.mp.model.MediaItem * @see com.foxinmy.weixin4j.mp.model.MediaItem
@ -351,7 +350,7 @@ public class WeixinProxy {
* @param mediaType * @param mediaType
* 媒体类型 * 媒体类型
* @return 素材列表 * @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)} * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#listMaterialMedia(MediaType, int, int)}
* @throws WeixinException * @throws WeixinException
*/ */
@ -651,7 +650,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.mp.api.MassApi * @see com.foxinmy.weixin4j.mp.api.MassApi
* @see com.foxinmy.weixin4j.tuple.Video * @see com.foxinmy.weixin4j.tuple.Video
* @see com.foxinmy.weixin4j.tuple.MpVideo * @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 { public String uploadMassVideo(Video video) throws WeixinException {
return massApi.uploadVideo(video); return massApi.uploadVideo(video);
@ -749,7 +748,7 @@ public class WeixinProxy {
* @see com.foxinmy.weixin4j.tuple.MassTuple * @see com.foxinmy.weixin4j.tuple.MassTuple
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E6.A0.B9.E6.8D.AEOpenID.E5.88.97.E8.A1.A8.E7.BE.A4.E5.8F.91.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8D.E5.8F.AF.E7.94.A8.EF.BC.8C.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.8F.AF.E7.94.A8.E3.80.91">根据openid群发</a> * href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E6.A0.B9.E6.8D.AEOpenID.E5.88.97.E8.A1.A8.E7.BE.A4.E5.8F.91.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8D.E5.8F.AF.E7.94.A8.EF.BC.8C.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.8F.AF.E7.94.A8.E3.80.91">根据openid群发</a>
* @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)} * @see {@link com.foxinmy.weixin4j.mp.api.UserApi#getUser(String)}
*/ */
public String massByOpenIds(MassTuple tuple, String... openIds) public String massByOpenIds(MassTuple tuple, String... openIds)
@ -798,8 +797,10 @@ public class WeixinProxy {
/** /**
* 预览群发消息</br> 开发者可通过该接口发送消息给指定用户在手机端查看消息的样式和排版 * 预览群发消息</br> 开发者可通过该接口发送消息给指定用户在手机端查看消息的样式和排版
* *
* @param openId * @param toUser
* 接收用户的ID * 接收用户的openID
* @param toWxName
* 接收用户的微信号 towxname和touser同时赋值时以towxname优先
* @param tuple * @param tuple
* 消息元件 * 消息元件
* @return 处理结果 * @return 处理结果
@ -809,9 +810,9 @@ public class WeixinProxy {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E9.A2.84.E8.A7.88.E6.8E.A5.E5.8F.A3.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91">预览群发消息</a> * href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E9.A2.84.E8.A7.88.E6.8E.A5.E5.8F.A3.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91">预览群发消息</a>
*/ */
public JsonResult previewMassNews(String openId, MassTuple tuple) public JsonResult previewMassNews(String toUser, String toWxName,
throws WeixinException { MassTuple tuple) throws WeixinException {
return massApi.previewMassNews(openId, tuple); return massApi.previewMassNews(toUser, toWxName, tuple);
} }
/** /**

View File

@ -73,7 +73,7 @@ public class MassApi extends MpApi {
* href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html">高级群发</a> * href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html">高级群发</a>
* @see com.foxinmy.weixin4j.tuple.Video * @see com.foxinmy.weixin4j.tuple.Video
* @see com.foxinmy.weixin4j.tuple.MpVideo * @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 { public String uploadVideo(Video video) throws WeixinException {
String video_upload_uri = getRequestUri("video_upload_uri"); String video_upload_uri = getRequestUri("video_upload_uri");
@ -274,8 +274,10 @@ public class MassApi extends MpApi {
/** /**
* 预览群发消息</br> 开发者可通过该接口发送消息给指定用户在手机端查看消息的样式和排版 * 预览群发消息</br> 开发者可通过该接口发送消息给指定用户在手机端查看消息的样式和排版
* *
* @param openId * @param toUser
* 接收用户的ID * 接收用户的openID
* @param toWxName
* 接收用户的微信号 towxname和touser同时赋值时以towxname优先
* @param tuple * @param tuple
* 消息元件 * 消息元件
* @return 处理结果 * @return 处理结果
@ -284,11 +286,12 @@ public class MassApi extends MpApi {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E9.A2.84.E8.A7.88.E6.8E.A5.E5.8F.A3.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91">预览群发消息</a> * href="http://mp.weixin.qq.com/wiki/15/5380a4e6f02f2ffdc7981a8ed7a40753.html#.E9.A2.84.E8.A7.88.E6.8E.A5.E5.8F.A3.E3.80.90.E8.AE.A2.E9.98.85.E5.8F.B7.E4.B8.8E.E6.9C.8D.E5.8A.A1.E5.8F.B7.E8.AE.A4.E8.AF.81.E5.90.8E.E5.9D.87.E5.8F.AF.E7.94.A8.E3.80.91">预览群发消息</a>
*/ */
public JsonResult previewMassNews(String openId, MassTuple tuple) public JsonResult previewMassNews(String toUser, String toWxName,
throws WeixinException { MassTuple tuple) throws WeixinException {
String msgtype = tuple.getMessageType(); String msgtype = tuple.getMessageType();
JSONObject obj = new JSONObject(); 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, JSON.toJSON(tuple));
obj.put("msgtype", msgtype); obj.put("msgtype", msgtype);
String mass_preview_uri = getRequestUri("mass_preview_uri"); String mass_preview_uri = getRequestUri("mass_preview_uri");

View File

@ -15,17 +15,19 @@ import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference; import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.deserializer.ExtraProcessor; import com.alibaba.fastjson.parser.deserializer.ExtraProcessor;
import com.foxinmy.weixin4j.exception.WeixinException; 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.FormBodyPart;
import com.foxinmy.weixin4j.http.apache.InputStreamBody; import com.foxinmy.weixin4j.http.apache.InputStreamBody;
import com.foxinmy.weixin4j.http.apache.StringBody; 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.JsonResult;
import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.model.Consts; 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.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.token.TokenHolder;
import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.type.MediaType; 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.IOUtil;
import com.foxinmy.weixin4j.util.ObjectId; import com.foxinmy.weixin4j.util.ObjectId;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
/** /**
* 素材相关API * 素材相关API
@ -73,12 +76,12 @@ public class MediaApi extends MpApi {
MediaType mediaType = null; MediaType mediaType = null;
if ("bmp/png/jpeg/jpg/gif".contains(mediaTypeKey)) { if ("bmp/png/jpeg/jpg/gif".contains(mediaTypeKey)) {
mediaType = MediaType.image; mediaType = MediaType.image;
} else if ("amr/mp3".contains(mediaTypeKey)) { } else if ("mp3/wma/wav/amr".contains(mediaTypeKey)) {
mediaType = MediaType.voice; mediaType = MediaType.voice;
} else if ("mp3/wma/wav/amr".equals(mediaTypeKey)) { } else if ("mp4".equals(mediaTypeKey)) {
mediaType = MediaType.video; mediaType = MediaType.video;
} else { } else {
throw new WeixinException("unknown mediaType:" + mediaTypeKey); throw new WeixinException("cannot handle mediaType:" + mediaTypeKey);
} }
return uploadMedia(new FileInputStream(file), mediaType, isMaterial); return uploadMedia(new FileInputStream(file), mediaType, isMaterial);
} }
@ -102,7 +105,6 @@ public class MediaApi extends MpApi {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久素材</a> * href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久素材</a>
* @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.type.MediaType
* @see com.foxinmy.weixin4j.mp.api.MediaApi
* @throws WeixinException * @throws WeixinException
*/ */
public String uploadMedia(InputStream is, MediaType mediaType, public String uploadMedia(InputStream is, MediaType mediaType,
@ -125,12 +127,12 @@ public class MediaApi extends MpApi {
new FormBodyPart("type", new StringBody(mediaType new FormBodyPart("type", new StringBody(mediaType
.name(), Consts.UTF_8))); .name(), Consts.UTF_8)));
} else { } else {
String file_upload_uri = getRequestUri("file_upload_uri"); String media_upload_uri = getRequestUri("media_upload_uri");
response = weixinClient.post(String.format(file_upload_uri, response = weixinClient.post(String.format(media_upload_uri,
token.getAccessToken(), mediaType), new FormBodyPart( token.getAccessToken(), mediaType.name()),
"media", new InputStreamBody(is, mediaType new FormBodyPart("media", new InputStreamBody(is,
.getContentType().getMimeType(), ObjectId.get() mediaType.getContentType().getMimeType(),
.toHexString()))); ObjectId.get().toHexString())));
} }
} catch (UnsupportedEncodingException e) { } catch (UnsupportedEncodingException e) {
throw new WeixinException(e); throw new WeixinException(e);
@ -162,7 +164,8 @@ public class MediaApi extends MpApi {
*/ */
public File downloadMediaFile(String mediaId, boolean isMaterial) public File downloadMediaFile(String mediaId, boolean isMaterial)
throws WeixinException { 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); File file = new File(media_path + File.separator + mediaId);
if (file.exists()) { if (file.exists()) {
return file; return file;
@ -198,7 +201,7 @@ public class MediaApi extends MpApi {
* 媒体ID * 媒体ID
* @param isMaterial * @param isMaterial
* 是否下载永久素材 * 是否下载永久素材
* @return 二进制数据包 * @return 二进制数据包(需自行判断类型)
* @throws WeixinException * @throws WeixinException
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/11/07b6b76a6b6e8848e855a435d5e34a5f.html">下载临时媒体素材</a> * href="http://mp.weixin.qq.com/wiki/11/07b6b76a6b6e8848e855a435d5e34a5f.html">下载临时媒体素材</a>
@ -208,20 +211,23 @@ public class MediaApi extends MpApi {
public byte[] downloadMedia(String mediaId, boolean isMaterial) public byte[] downloadMedia(String mediaId, boolean isMaterial)
throws WeixinException { throws WeixinException {
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
WeixinResponse response = null; try {
if (isMaterial) { if (isMaterial) {
JSONObject media = new JSONObject(); String material_media_download_uri = getRequestUri("material_media_download_uri");
media.put("media_id", mediaId); HttpPost method = new HttpPost(String.format(
String material_media_download_uri = getRequestUri("material_media_download_uri"); material_media_download_uri, token.getAccessToken()));
response = weixinClient.post( method.setEntity(new StringEntity(String.format(
String.format(material_media_download_uri, "{\"media_id\":\"%s\"}", mediaId)));
token.getAccessToken()), media.toJSONString()); return weixinClient.execute(method).getContent();
} else { } else {
String file_download_uri = getRequestUri("file_download_uri"); String meida_download_uri = getRequestUri("meida_download_uri");
response = weixinClient.get(String.format(file_download_uri, HttpGet method = new HttpGet(String.format(meida_download_uri,
token.getAccessToken(), mediaId)); 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的视频文件 * 大小不超过1M且格式为MP4的视频文件
* @param title * @param title
* 视频标题 * 视频标题
@ -337,29 +343,36 @@ public class MediaApi extends MpApi {
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久媒体素材</a> * href="http://mp.weixin.qq.com/wiki/14/7e6c03263063f4813141c3e17dd4350a.html">上传永久媒体素材</a>
* @throws WeixinException * @throws WeixinException
* @throws IOException
*/ */
public String uploadMaterialVideo(File file, String title, public String uploadMaterialVideo(InputStream is, String title,
String introduction) throws WeixinException, IOException { String introduction) throws WeixinException {
String material_media_upload_uri = getRequestUri("material_media_upload_uri"); String material_media_upload_uri = getRequestUri("material_media_upload_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
try { try {
JSONObject description = new JSONObject(); JSONObject description = new JSONObject();
description.put("title", title); description.put("title", title);
description.put("introduction", introduction); description.put("introduction", introduction);
byte[] bytes = IOUtil.toByteArray(new FileInputStream(file));
WeixinResponse response = weixinClient.post( WeixinResponse response = weixinClient.post(
String.format(material_media_upload_uri, String.format(material_media_upload_uri,
token.getAccessToken()), token.getAccessToken()),
new FormBodyPart("media", new ByteArrayBody(bytes, file new FormBodyPart("media", new InputStreamBody(is,
.getName())), MediaType.video.getContentType().getMimeType(),
ObjectId.get().toHexString())),
new FormBodyPart("type", new StringBody(MediaType.video new FormBodyPart("type", new StringBody(MediaType.video
.name(), Consts.UTF_8)), .name(), Consts.UTF_8)),
new FormBodyPart("description", new StringBody(description new FormBodyPart("description", new StringBody(description
.toJSONString(), Consts.UTF_8))); .toJSONString(), Consts.UTF_8)));
return response.getAsJson().getString("media_id"); return response.getAsJson().getString("media_id");
} catch (UnsupportedEncodingException e) { } 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 总数对象 * @return 总数对象
* @throws WeixinException * @throws WeixinException
* @see com.foxinmy.weixin4j.mp.model.MediaCounter * @see com.foxinmy.weixin4j.model.MediaCounter
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html">获取素材总数</a> * href="http://mp.weixin.qq.com/wiki/16/8cc64f8c189674b421bee3ed403993b8.html">获取素材总数</a>
*/ */
@ -393,9 +406,9 @@ public class MediaApi extends MpApi {
* 返回素材的数量取值在1到20之间 * 返回素材的数量取值在1到20之间
* @return 媒体素材的记录对象 * @return 媒体素材的记录对象
* @throws WeixinException * @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.type.MediaType
* @see com.foxinmy.weixin4j.mp.model.MediaItem * @see com.foxinmy.weixin4j.model.MediaItem
* @see <a * @see <a
* href="http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html">获取素材列表</a> * href="http://mp.weixin.qq.com/wiki/12/2108cd7aafff7f388f41f37efa710204.html">获取素材列表</a>
*/ */

View File

@ -24,7 +24,7 @@ public class MpApi extends BaseApi {
} }
@Override @Override
protected String getConfigValue(String key) { protected ResourceBundle weixinBundle() {
return WEIXIN_BUNDLE.getString(key); return WEIXIN_BUNDLE;
} }
} }

View File

@ -12,6 +12,7 @@ import com.foxinmy.weixin4j.model.Token;
import com.foxinmy.weixin4j.mp.model.QRParameter; import com.foxinmy.weixin4j.mp.model.QRParameter;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
/** /**
* 二维码相关API * 二维码相关API
@ -89,7 +90,8 @@ public class QrApi extends MpApi {
* @see com.foxinmy.weixin4j.mp.model.QRParameter * @see com.foxinmy.weixin4j.mp.model.QRParameter
*/ */
public File getQRFile(QRParameter parameter) throws WeixinException { 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() String filename = String.format("%s_%s_%d.jpg", parameter.getQrType()
.name(), parameter.getSceneValue(), parameter .name(), parameter.getSceneValue(), parameter
.getExpireSeconds()); .getExpireSeconds());

View File

@ -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_ticket_uri={api_cgi_url}/qrcode/create?access_token=%s
qr_image_uri={mp_base_url}/showqrcode?ticket=%s qr_image_uri={mp_base_url}/showqrcode?ticket=%s
# \u4e0a\u4f20\u5a92\u4f53\u6587\u4ef6 # \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 # \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 # \u53d1\u9001\u5ba2\u670d\u6d88\u606f
custom_notify_uri={api_cgi_url}/message/custom/send?access_token=%s custom_notify_uri={api_cgi_url}/message/custom/send?access_token=%s
# \u521b\u5efa\u5206\u7ec4 # \u521b\u5efa\u5206\u7ec4

View File

@ -96,7 +96,7 @@ public class MassTest extends TokenTest {
@Test @Test
public void previewMass() throws WeixinException { public void previewMass() throws WeixinException {
JsonResult result = massApi.previewMassNews( JsonResult result = massApi.previewMassNews(
"oyFLst1bqtuTcxK-ojF8hOGtLQao", new Text("test")); "oyFLst1bqtuTcxK-ojF8hOGtLQao", null, new Text("test"));
Assert.assertEquals(0, result.getCode()); Assert.assertEquals(0, result.getCode());
} }

View File

@ -1,6 +1,7 @@
package com.foxinmy.weixin4j.mp.test; package com.foxinmy.weixin4j.mp.test;
import java.io.File; import java.io.File;
import java.io.FileInputStream;
import java.io.IOException; import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -11,10 +12,10 @@ import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.JsonResult; 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.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.tuple.MpArticle;
import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.type.MediaType;
@ -47,11 +48,9 @@ public class MediaTest extends TokenTest {
@Test @Test
public void download1() throws WeixinException, IOException { public void download1() throws WeixinException, IOException {
File file = mediaApi byte[] content = mediaApi.downloadMedia(
.downloadMediaFile( "jM5OWhnYb2DgrNm97HGj8aUdsZcweQc93tnwbH1mERo", true);
"1Vgd1R5DdznSc3rPxd-sNZ3pLt54cejhJ5ItuNcCgrqoQArNANWy5oxso_r9KNlE", Assert.assertTrue(content != null);
false);
Assert.assertTrue(file.exists());
} }
@Test @Test
@ -66,8 +65,8 @@ public class MediaTest extends TokenTest {
@Test @Test
public void uploadMaterialVideo() throws IOException, WeixinException { public void uploadMaterialVideo() throws IOException, WeixinException {
File file = new File("/Users/jy/Downloads/test.jpg"); File file = new File("/Users/jy/Downloads/test.jpg");
String mediaId = mediaApi.uploadMaterialVideo(file, "title", String mediaId = mediaApi.uploadMaterialVideo(
"introduction"); new FileInputStream(file), "title", "introduction");
// Sy1KOLsi4ri3kB3TYUuculVelcW2I7W6BrfGwkGvSW8beTCAarxuGQLjuNJChJr8 // Sy1KOLsi4ri3kB3TYUuculVelcW2I7W6BrfGwkGvSW8beTCAarxuGQLjuNJChJr8
Assert.assertNotNull(mediaId); Assert.assertNotNull(mediaId);
System.err.println(mediaId); System.err.println(mediaId);

View File

@ -22,6 +22,7 @@ import com.foxinmy.weixin4j.token.FileTokenStorager;
import com.foxinmy.weixin4j.type.IdQuery; import com.foxinmy.weixin4j.type.IdQuery;
import com.foxinmy.weixin4j.type.IdType; import com.foxinmy.weixin4j.type.IdType;
import com.foxinmy.weixin4j.type.TradeType; import com.foxinmy.weixin4j.type.TradeType;
import com.foxinmy.weixin4j.util.ConfigUtil;
public class PayTest { public class PayTest {
private final static Pay2Api PAY2; private final static Pay2Api PAY2;
@ -31,7 +32,8 @@ public class PayTest {
static { static {
ACCOUNT2 = new WeixinPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret", ACCOUNT2 = new WeixinPayAccount("请填入v2版本的appid", "请填入v2版本的appSecret",
"请填入v3版本的paysignkey", "请填入v2版本的partnerId", "请填入v2版本的partnerKey"); "请填入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", ACCOUNT3 = new WeixinPayAccount("请填入v3版本的appid", "请填入v3版本的appSecret",
"请填入v3版本的paysignkey", "请填入v3版本的mchid"); "请填入v3版本的paysignkey", "请填入v3版本的mchid");
PAY3 = new WeixinPayProxy(ACCOUNT3); PAY3 = new WeixinPayProxy(ACCOUNT3);

View File

@ -28,7 +28,8 @@ public class TokenTest {
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
tokenHolder = new TokenHolder(new WeixinTokenCreator( tokenHolder = new TokenHolder(new WeixinTokenCreator(
weixinAccount.getId(), weixinAccount.getSecret()), weixinAccount.getId(), weixinAccount.getSecret()),
new FileTokenStorager()); new FileTokenStorager(ConfigUtil.getValue(
"token_path", "/tmp/weixin4j/token")));
} }
@Test @Test

View File

@ -69,3 +69,7 @@
* 2015-06-26 * 2015-06-26
+ 管理成员新增头像参数 + 管理成员新增头像参数
* 2015-07-04
+ 新增[媒体素材接口](src/main/java/com/foxinmy/weixin4j/qy/api/MediaApi.java)

View File

@ -9,6 +9,9 @@ import com.alibaba.fastjson.JSONObject;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.JsonResult;
import com.foxinmy.weixin4j.model.Button; 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.AgentApi;
import com.foxinmy.weixin4j.qy.api.BatchApi; import com.foxinmy.weixin4j.qy.api.BatchApi;
import com.foxinmy.weixin4j.qy.api.HelperApi; 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.qy.type.UserStatus;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.token.TokenStorager; import com.foxinmy.weixin4j.token.TokenStorager;
import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.type.MediaType;
/** /**
@ -204,75 +208,203 @@ public class WeixinProxy {
/** /**
* 上传媒体文件 * 上传媒体文件
* *
* @param agentid
* 企业应用ID(<font color="red">大于0时视为上传永久媒体文件</font>)
* @param file * @param file
* 媒体对象 * 文件对象
* @return 上传到微信服务器返回的媒体标识 * @return 上传到微信服务器返回的媒体标识
* @see com.foxinmy.weixin4j.qy.api.MediaApi * @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 WeixinException
* @throws IOException * @throws IOException
*/ */
public String uploadMedia(File file) throws WeixinException, IOException { public String uploadMedia(int agentid, File file) throws WeixinException,
return mediaApi.uploadMedia(file); IOException {
return mediaApi.uploadMedia(agentid, file);
} }
/** /**
* 上传媒体文件(完全公开所有管理员均可调用media_id可以共享) * 上传媒体文件
* <p> * <p>
* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}, * 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789},
* 否则抛出异常. * 否则抛出异常.
* </p> * </p>
* *
* @param agentid
* 企业应用ID(<font color="red">大于0时视为上传永久媒体文件</font>)
* @param is * @param is
* 媒体数据流 * 媒体数据流
* @param mediaType * @param mediaType
* 媒体类型 * 媒体类型
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see com.foxinmy.weixin4j.type.MediaType
* @return 上传到微信服务器返回的媒体标识 * @return 上传到微信服务器返回的媒体标识
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传媒体文件说明</a>
* @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 com.foxinmy.weixin4j.qy.api.MediaApi
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">获取媒体说明</a> * 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">上传临时素材文件说明</a>
* @see <a
* href="http://http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E6%B0%B8%E4%B9%85%E7%B4%A0%E6%9D%90">上传永久素材文件说明</a>
* @throws WeixinException * @throws WeixinException
*/ */
public byte[] downloadMedia(String mediaId) throws WeixinException { public String uploadMedia(int agentid, InputStream is, MediaType mediaType)
return mediaApi.downloadMedia(mediaId); throws WeixinException {
return mediaApi.uploadMedia(agentid, is, mediaType);
} }
/** /**
* 下载媒体文件(完全公开所有管理员均可调用media_id可以共享) * 下载媒体文件
* <p>
* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常.
* </p>
* *
* @param agentid
* 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>)
* @param mediaId * @param mediaId
* 存储在微信服务器上的媒体标识 * 存储在微信服务器上的媒体标识
* @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置
* @throws WeixinException * @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(<font color="red">大于0时视为获取永久媒体文件</font>)
* @param mediaId
* 媒体ID
* @return 二进制数据包(需自行判断类型)
* @see com.foxinmy.weixin4j.qy.api.MediaApi * @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">获取媒体说明</a> * 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">获取临时媒体说明</a>
* @see com.foxinmy.weixin4j.type.MediaType * @see <a
* @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%E6%B0%B8%E4%B9%85%E7%B4%A0%E6%9D%90">获取永久媒体说明</a>
* @throws WeixinException
*/ */
public File downloadMediaFile(String mediaId) throws WeixinException { public byte[] downloadMedia(int agentid, String mediaId)
return mediaApi.downloadMediaFile(mediaId); throws WeixinException {
return mediaApi.downloadMedia(agentid, mediaId);
}
/**
* 上传永久图文素材
* <p>
* 新增的永久素材也可以在公众平台官网素材管理模块中看到,永久素材的数量是有上限的请谨慎新增图文消息素材和图片素材的上限为5000
* 其他类型为1000
* </P>
*
* @param agentid
* 企业应用的id
* @param articles
* 图文列表
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @see com.foxinmy.weixin4j.qy.api.MediaApi
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E6%B0%B8%E4%B9%85%E7%B4%A0%E6%9D%90">上传永久媒体素材</a>
* @see com.foxinmy.weixin4j.tuple.MpArticle
*/
public String uploadMaterialArticle(int agentid, List<MpArticle> 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 <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%A0%E9%99%A4%E6%B0%B8%E4%B9%85%E7%B4%A0%E6%9D%90">删除永久媒体素材</a>
*/
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 <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BF%AE%E6%94%B9%E6%B0%B8%E4%B9%85%E5%9B%BE%E6%96%87%E7%B4%A0%E6%9D%90">修改永久媒体素材</a>
* @see com.foxinmy.weixin4j.tuple.MpArticle
*/
public String updateMaterialArticle(int agentid, String mediaId,
List<MpArticle> 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 <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%B4%A0%E6%9D%90%E6%80%BB%E6%95%B0">获取素材总数</a>
*/
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 <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%B4%A0%E6%9D%90%E5%88%97%E8%A1%A8">获取素材列表</a>
*/
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<MediaItem> listAllMaterialMedia(int agentid, MediaType mediaType)
throws WeixinException {
return mediaApi.listAllMaterialMedia(agentid, mediaType);
} }
/** /**

View File

@ -8,6 +8,7 @@ import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.StringWriter; import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -17,21 +18,28 @@ import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject; import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.PropertyFilter; import com.alibaba.fastjson.serializer.PropertyFilter;
import com.foxinmy.weixin4j.exception.WeixinException; 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.FormBodyPart;
import com.foxinmy.weixin4j.http.apache.InputStreamBody; 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.http.weixin.WeixinResponse;
import com.foxinmy.weixin4j.model.Consts; 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.model.Token;
import com.foxinmy.weixin4j.qy.model.Callback; import com.foxinmy.weixin4j.qy.model.Callback;
import com.foxinmy.weixin4j.qy.model.Party; import com.foxinmy.weixin4j.qy.model.Party;
import com.foxinmy.weixin4j.qy.model.User; import com.foxinmy.weixin4j.qy.model.User;
import com.foxinmy.weixin4j.token.TokenHolder; import com.foxinmy.weixin4j.token.TokenHolder;
import com.foxinmy.weixin4j.tuple.MpArticle;
import com.foxinmy.weixin4j.type.MediaType; import com.foxinmy.weixin4j.type.MediaType;
import com.foxinmy.weixin4j.util.ConfigUtil; import com.foxinmy.weixin4j.util.ConfigUtil;
import com.foxinmy.weixin4j.util.FileUtil; import com.foxinmy.weixin4j.util.FileUtil;
import com.foxinmy.weixin4j.util.IOUtil; import com.foxinmy.weixin4j.util.IOUtil;
import com.foxinmy.weixin4j.util.ObjectId; import com.foxinmy.weixin4j.util.ObjectId;
import com.foxinmy.weixin4j.util.StringUtil; import com.foxinmy.weixin4j.util.StringUtil;
import com.foxinmy.weixin4j.util.Weixin4jConst;
/** /**
* 媒体相关API * 媒体相关API
@ -41,7 +49,7 @@ import com.foxinmy.weixin4j.util.StringUtil;
* @date 2014年9月25日 * @date 2014年9月25日
* @since JDK 1.7 * @since JDK 1.7
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E7%AE%A1%E7%90%86%E5%A4%9A%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">管理多媒体文件</a> * 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">管理素材文件</a>
* @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.type.MediaType
*/ */
public class MediaApi extends QyApi { public class MediaApi extends QyApi {
@ -55,96 +63,118 @@ public class MediaApi extends QyApi {
/** /**
* 上传媒体文件 * 上传媒体文件
* *
* @param agentid
* 企业应用ID(<font color="red">大于0时视为上传永久媒体文件</font>)
* @param file * @param file
* 媒体对象 * 文件对象
* @return 上传到微信服务器返回的媒体标识 * @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 WeixinException
* @throws IOException * @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()); String mediaTypeKey = IOUtil.getExtension(file.getName());
if (StringUtil.isBlank(mediaTypeKey)) { if (StringUtil.isBlank(mediaTypeKey)) {
mediaTypeKey = FileUtil.getFileType(file); mediaTypeKey = FileUtil.getFileType(file);
} }
MediaType mediaType = null; MediaType mediaType = null;
if (mediaTypeKey.equals("jpg")) { if ("bmp/png/jpeg/jpg/gif".contains(mediaTypeKey)) {
mediaType = MediaType.image; mediaType = MediaType.image;
} else if ("amr/mp3".contains(mediaTypeKey)) { } else if ("mp3/wma/wav/amr".contains(mediaTypeKey)) {
mediaType = MediaType.voice; mediaType = MediaType.voice;
} else if (mediaTypeKey.equals("mp4")) { } else if ("mp4".equals(mediaTypeKey)) {
mediaType = MediaType.video; mediaType = MediaType.video;
} else { } else {
mediaType = MediaType.file; mediaType = MediaType.file;
} }
return uploadMedia(new FileInputStream(file), mediaType); return uploadMedia(agentid, new FileInputStream(file), mediaType);
} }
/** /**
* 上传媒体文件(完全公开所有管理员均可调用media_id可以共享) * 上传媒体文件
* <p> * <p>
* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}, * 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789},
* 否则抛出异常. * 否则抛出异常.
* </p> * </p>
* *
* @param agentid
* 企业应用ID(<font color="red">大于0时视为上传永久媒体文件</font>)
* @param is * @param is
* 媒体数据流 * 媒体数据流
* @param mediaType * @param mediaType
* 媒体类型 * 媒体类型
* @return 上传到微信服务器返回的媒体标识 * @return 上传到微信服务器返回的媒体标识
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">上传媒体文件说明</a> * 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">上传临时素材文件说明</a>
* @see <a
* href="http://http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E6%B0%B8%E4%B9%85%E7%B4%A0%E6%9D%90">上传永久素材文件说明</a>
* @throws WeixinException * @throws WeixinException
*/ */
public String uploadMedia(InputStream is, MediaType mediaType) public String uploadMedia(int agentid, InputStream is, MediaType mediaType)
throws WeixinException { throws WeixinException {
String file_upload_uri = getRequestUri("file_upload_uri");
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
if (mediaType == null || mediaType == MediaType.news) { if (mediaType == null) {
mediaType = MediaType.file; mediaType = MediaType.file;
} else if (mediaType == MediaType.thumb) { } else if (mediaType == MediaType.thumb) {
mediaType = MediaType.image; 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 { try {
is.close(); WeixinResponse response = null;
} catch (IOException e) { 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可以共享) * 下载媒体文件
* <p>
* 正常情况下返回表头如Content-Type: image/jpeg,否则抛出异常.
* </p>
* *
* @param agentid
* 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>)
* @param mediaId * @param mediaId
* 存储在微信服务器上的媒体标识 * 存储在微信服务器上的媒体标识
* @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置
* @throws WeixinException * @throws WeixinException
* @throws IOException
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">获取媒体说明</a>
* @see com.foxinmy.weixin4j.type.MediaType * @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 { public File downloadMediaFile(int agentid, String mediaId)
String media_path = ConfigUtil.getValue("media_path"); throws WeixinException {
String media_path = ConfigUtil.getValue("media_path",
Weixin4jConst.DEFAULT_MEDIA_PATH);
File file = new File(media_path + File.separator + mediaId); File file = new File(media_path + File.separator + mediaId);
if (file.exists()) { if (file.exists()) {
return file; return file;
} }
byte[] datas = downloadMedia(mediaId); byte[] datas = downloadMedia(agentid, mediaId);
OutputStream os = null; OutputStream os = null;
try { try {
boolean flag = file.createNewFile(); if (file.createNewFile()) {
if (flag) {
os = new FileOutputStream(file); os = new FileOutputStream(file);
os.write(datas); os.write(datas);
} else { } else {
@ -166,21 +196,216 @@ public class MediaApi extends QyApi {
} }
/** /**
* 下载媒体文件(完全公开所有管理员均可调用media_id可以共享) * 下载媒体文件
* *
* @param agentid
* 企业应用Id(<font color="red">大于0时视为获取永久媒体文件</font>)
* @param mediaId * @param mediaId
* 媒体ID * 媒体ID
* @return 二进制数据包 * @return 二进制数据包(需自行判断类型)
* @see <a * @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E5%AA%92%E4%BD%93%E6%96%87%E4%BB%B6">获取媒体说明</a> * 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">获取临时媒体说明</a>
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E6%B0%B8%E4%B9%85%E7%B4%A0%E6%9D%90">获取永久媒体说明</a>
* @throws WeixinException * @throws WeixinException
*/ */
public byte[] downloadMedia(String mediaId) throws WeixinException { public byte[] downloadMedia(int agentid, String mediaId)
throws WeixinException {
Token token = tokenHolder.getToken(); 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);
}
}
/**
* 上传永久图文素材
* <p>
* 新增的永久素材也可以在公众平台官网素材管理模块中看到,永久素材的数量是有上限的请谨慎新增图文消息素材和图片素材的上限为5000
* 其他类型为1000
* </P>
*
* @param agentid
* 企业应用的id
* @param articles
* 图文列表
* @return 上传到微信服务器返回的媒体标识
* @throws WeixinException
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%B8%8A%E4%BC%A0%E6%B0%B8%E4%B9%85%E7%B4%A0%E6%9D%90">上传永久媒体素材</a>
* @see com.foxinmy.weixin4j.tuple.MpArticle
*/
public String uploadMaterialArticle(int agentid, List<MpArticle> 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 <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E5%88%A0%E9%99%A4%E6%B0%B8%E4%B9%85%E7%B4%A0%E6%9D%90">删除永久媒体素材</a>
*/
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( WeixinResponse response = weixinClient.get(String.format(
file_download_uri, token.getAccessToken(), mediaId)); material_media_del_uri, token.getAccessToken(), mediaId,
return response.getContent(); agentid));
return response.getAsJsonResult();
}
/**
* 修改永久图文素材
*
* @param agentid
* 企业应用的id
* @param mediaId
* 上传后的media_id
* @param articles
* 图文列表
* @return 操作结果
* @throws WeixinException
* @see <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E4%BF%AE%E6%94%B9%E6%B0%B8%E4%B9%85%E5%9B%BE%E6%96%87%E7%B4%A0%E6%9D%90">修改永久媒体素材</a>
* @see com.foxinmy.weixin4j.tuple.MpArticle
*/
public String updateMaterialArticle(int agentid, String mediaId,
List<MpArticle> 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 <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%B4%A0%E6%9D%90%E6%80%BB%E6%95%B0">获取素材总数</a>
*/
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 <a
* href="http://qydev.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96%E7%B4%A0%E6%9D%90%E5%88%97%E8%A1%A8">获取素材列表</a>
*/
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<MediaItem> listAllMaterialMedia(int agentid, MediaType mediaType)
throws WeixinException {
int offset = 0;
int count = 20;
List<MediaItem> mediaList = new ArrayList<MediaItem>();
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 <T> String batchUpload(String batchName, List<T> models) private <T> String batchUpload(String batchName, List<T> models)
throws WeixinException { throws WeixinException {
JSONObject csvObj = JSON.parseObject(getConfigValue(batchName));
JSONArray columns = csvObj.getJSONArray("column");
StringWriter writer = new StringWriter(); StringWriter writer = new StringWriter();
writer.write(csvObj.getString("header"));
final Map<String, Object> column = new LinkedHashMap<String, Object>();
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 { try {
writer.close(); JSONObject csvObj = JSON.parseObject(weixinBundle().getString(
} catch (IOException e) { batchName));
; JSONArray columns = csvObj.getJSONArray("column");
writer.write(csvObj.getString("header"));
final Map<String, Object> column = new LinkedHashMap<String, Object>();
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;
} }
} }

View File

@ -33,7 +33,7 @@ public class QyApi extends BaseApi {
} }
@Override @Override
protected String getConfigValue(String key) { protected ResourceBundle weixinBundle() {
return WEIXIN_BUNDLE.getString(key); return WEIXIN_BUNDLE;
} }
} }

View File

@ -119,7 +119,7 @@ public class UserApi extends QyApi {
} }
if (avatar != null) { if (avatar != null) {
obj.put("avatar_mediaid", obj.put("avatar_mediaid",
mediaApi.uploadMedia(avatar, MediaType.image)); mediaApi.uploadMedia(0, avatar, MediaType.image));
} }
Token token = tokenHolder.getToken(); Token token = tokenHolder.getToken();
WeixinResponse response = weixinClient.post( WeixinResponse response = weixinClient.post(

View File

@ -100,3 +100,22 @@ suite_set_agent_uri={api_base_url}/service/set_agent?suite_access_token=%s
userid2openid_uri={api_base_url}/user/convert_to_openid?access_token=%s userid2openid_uri={api_base_url}/user/convert_to_openid?access_token=%s
# openid\u8f6c\u6362\u6210userid # openid\u8f6c\u6362\u6210userid
openid2userid_uri={api_base_url}/user/convert_to_userid?access_token=%s 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

View File

@ -70,7 +70,7 @@ public class User implements Serializable {
/** /**
* 启用/禁用成员1表示启用成员0表示禁用成员 * 启用/禁用成员1表示启用成员0表示禁用成员
*/ */
private int enable; private Integer enable;
/** /**
* 非必须 扩展属性扩展属性需要在WEB管理端创建后才生效否则忽略未知属性的赋值 * 非必须 扩展属性扩展属性需要在WEB管理端创建后才生效否则忽略未知属性的赋值
*/ */
@ -218,16 +218,23 @@ public class User implements Serializable {
this.status = status; this.status = status;
} }
public int getEnable() { public int getStatus() {
return status;
}
public Integer getEnable() {
return enable; return enable;
} }
@JSONField(serialize = false, deserialize = false) @JSONField(serialize = false, deserialize = false)
public boolean getFormatEnable() { 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; this.enable = enable;
} }

View File

@ -9,6 +9,7 @@ import org.junit.Test;
import com.foxinmy.weixin4j.exception.WeixinException; import com.foxinmy.weixin4j.exception.WeixinException;
import com.foxinmy.weixin4j.qy.api.MediaApi; import com.foxinmy.weixin4j.qy.api.MediaApi;
import com.foxinmy.weixin4j.type.MediaType;
/** /**
* 媒体上传下载测试 * 媒体上传下载测试
@ -30,8 +31,8 @@ public class MediaTest extends TokenTest {
@Test @Test
public void upload() throws IOException, WeixinException { public void upload() throws IOException, WeixinException {
File file = new File("/tmp/test.docx"); File file = new File("//Users/jy/Downloads/import_file.csv");
String mediaId = mediaApi.uploadMedia(file); String mediaId = mediaApi.uploadMedia(1, file);
// 1-1gpykXsR8bhNvO13-ZvskptCBxQF1UE535jFdCF63N2inGRAqEb-psF6eppjIIl // 1-1gpykXsR8bhNvO13-ZvskptCBxQF1UE535jFdCF63N2inGRAqEb-psF6eppjIIl
// 1CF6sBgWWFGY9s4JCEet5ASszsTuyHpeN1f2LWXADveqBlKoxSgb3cO401NEM7dNY // 1CF6sBgWWFGY9s4JCEet5ASszsTuyHpeN1f2LWXADveqBlKoxSgb3cO401NEM7dNY
Assert.assertNotNull(mediaId); Assert.assertNotNull(mediaId);
@ -41,7 +42,13 @@ public class MediaTest extends TokenTest {
@Test @Test
public void download() throws WeixinException, IOException { public void download() throws WeixinException, IOException {
File file = mediaApi File file = mediaApi
.downloadMediaFile("1CF6sBgWWFGY9s4JCEet5ASszsTuyHpeN1f2LWXADveqBlKoxSgb3cO401NEM7dNY"); .downloadMediaFile(1,
"jM5OWhnYb2DgrNm97HGj8aUdsZcweQc93tnwbH1mERo");
Assert.assertTrue(file.exists()); Assert.assertTrue(file.exists());
} }
@Test
public void listAll() throws WeixinException {
mediaApi.listAllMaterialMedia(1, MediaType.image);
}
} }

View File

@ -28,7 +28,8 @@ public class TokenTest {
WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount(); WeixinAccount weixinAccount = ConfigUtil.getWeixinAccount();
tokenHolder = new TokenHolder(new WeixinTokenCreator( tokenHolder = new TokenHolder(new WeixinTokenCreator(
weixinAccount.getId(), weixinAccount.getSecret()), weixinAccount.getId(), weixinAccount.getSecret()),
new FileTokenStorager()); new FileTokenStorager(ConfigUtil.getValue(
"token_path", "/tmp/weixin4j/token")));
} }
@Test @Test

View File

@ -71,10 +71,7 @@ public class UserTest extends TokenTest {
@Test @Test
public void list() throws WeixinException { public void list() throws WeixinException {
List<User> userList = userApi.listUser(1, true, UserStatus.BOTH, true); List<User> userList = userApi.listUser(3, true, UserStatus.BOTH, true);
Assert.assertFalse(userList.isEmpty());
System.out.println(userList);
userList = userApi.listUser(1);
Assert.assertFalse(userList.isEmpty()); Assert.assertFalse(userList.isEmpty());
System.out.println(userList); System.out.println(userList);
} }

View File

@ -56,7 +56,7 @@ public final class WeixinServerBootstrap {
/** /**
* 服务启动的默认端口 * 服务启动的默认端口
*/ */
public final static int DEFAULT_SERVERPORT = 80; public final static int DEFAULT_SERVERPORT = 30000;
/** /**
* 消息分发器 * 消息分发器
*/ */