diff --git a/CHANGE.md b/CHANGE.md index 8316f902..b5fd93a3 100644 --- a/CHANGE.md +++ b/CHANGE.md @@ -357,4 +357,8 @@ + 将微信支付模块移到base工程 - + **weixin4j-qy**: 管理成员新增头像参数 \ No newline at end of file + + **weixin4j-qy**: 管理成员新增头像参数 + +* 2015-06-27 + + + 媒体接口(MediaApi)中上传方法中的File类型调整为InputStream \ No newline at end of file diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/ContentType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/ContentType.java index 43f8d8be..1e1355ee 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/ContentType.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/http/ContentType.java @@ -40,6 +40,12 @@ public final class ContentType implements Serializable { Consts.UTF_8); public static final ContentType TEXT_PLAIN = create("text/plain", Consts.UTF_8); + public static final ContentType IMAGE_JPG = create("image/jpg", + Consts.UTF_8); + public static final ContentType AUDIO_MP3 = create("audio/mp3", + Consts.UTF_8); + public static final ContentType VIDEO_MPEG4 = create("video/mpeg4", + Consts.UTF_8); public static final ContentType TEXT_XML = create("text/xml", Consts.UTF_8); public static final ContentType WILDCARD = create("*/*", (Charset) null); diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/MediaType.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/MediaType.java index daca3d44..3c927496 100644 --- a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/MediaType.java +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/type/MediaType.java @@ -1,5 +1,7 @@ package com.foxinmy.weixin4j.type; +import com.foxinmy.weixin4j.http.ContentType; + /** * 上传的媒体类型 *
@@ -21,28 +23,18 @@ package com.foxinmy.weixin4j.type; * @since JDK 1.7 */ public enum MediaType { - image("jpg"), voice("amr/mp3"), video("mp4"), thumb("jpg"), file("unknown"), news( - ""); + image(ContentType.IMAGE_JPG), voice(ContentType.AUDIO_MP3), video( + ContentType.VIDEO_MPEG4), thumb(ContentType.IMAGE_JPG), file( + ContentType.APPLICATION_OCTET_STREAM), news( + ContentType.APPLICATION_OCTET_STREAM); - MediaType(String formatName) { - this.formatName = formatName; + MediaType(ContentType contentType) { + this.contentType = contentType; } - public static MediaType getMediaType(String key) { - if (key.equals("jpg")) { - return MediaType.image; - } else if ("amr/mp3".contains(key)) { - return MediaType.voice; - } else if (key.equals("mp4")) { - return MediaType.video; - } else { - return MediaType.file; - } - } + private ContentType contentType; - private String formatName; - - public String getFormatName() { - return formatName; + public ContentType getContentType() { + return contentType; } } diff --git a/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ObjectId.java b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ObjectId.java new file mode 100644 index 00000000..ccdd95b4 --- /dev/null +++ b/weixin4j-base/src/main/java/com/foxinmy/weixin4j/util/ObjectId.java @@ -0,0 +1,333 @@ +package com.foxinmy.weixin4j.util; + +/* + * Copyright (c) 2008-2014 MongoDB, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import java.net.NetworkInterface; +import java.nio.ByteBuffer; +import java.util.Date; +import java.util.Enumeration; +import java.util.Random; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** + *
+ * A globally unique identifier for objects. + *
+ * + *+ * Consists of 12 bytes, divided as follows: + *
+ *| 0 | + *1 | + *2 | + *3 | + *4 | + *5 | + *6 | + *7 | + *8 | + *9 | + *10 | + *11 | + *
| time | + *machine | + *pid | + *inc | + *||||||||
+ * Instances of this class are immutable. + *
+ * + * @mongodb.driver.manual core/object-id ObjectId + */ +public class ObjectId implements Comparable* 正常情况下返回{"type":"TYPE","media_id":"MEDIA_ID","created_at":123456789}, * 否则抛出异常. *
* - * @param fileName - * 文件名 - * @param data - * 媒体数据包 + * @param is + * 媒体数据流 * @param mediaType - * 媒体类型 + * 媒体文件类型:分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb) * @param isMaterial * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 * @see 上传下载说明 + * href="http://mp.weixin.qq.com/wiki/5/963fc70b80dc75483a271298a76a8d59.html">上传临时素材 + * @see 上传永久素材 + * @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.mp.api.MediaApi * @throws WeixinException */ - public String uploadMedia(String fileName, byte[] data, String mediaType, + public String uploadMedia(InputStream is, MediaType mediaType, boolean isMaterial) throws WeixinException { - return mediaApi.uploadMedia(fileName, data, mediaType, isMaterial); + return mediaApi.uploadMedia(is, mediaType, isMaterial); } /** @@ -203,13 +186,12 @@ public class WeixinProxy { * @throws WeixinException * @see 上传下载说明 - * @see com.foxinmy.weixin4j.type.MediaType * @see com.foxinmy.weixin4j.mp.api.MediaApi * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#downloadMedia(String)} */ - public File downloadMedia(String mediaId, MediaType mediaType, - boolean isMaterial) throws WeixinException { - return mediaApi.downloadMedia(mediaId, mediaType, isMaterial); + public File downloadMediaFile(String mediaId, boolean isMaterial) + throws WeixinException { + return mediaApi.downloadMediaFile(mediaId, isMaterial); } /** 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 fa366615..218ca1e8 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 @@ -4,6 +4,7 @@ import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.util.ArrayList; @@ -16,6 +17,7 @@ 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.apache.FormBodyPart; +import com.foxinmy.weixin4j.http.apache.InputStreamBody; import com.foxinmy.weixin4j.http.apache.StringBody; import com.foxinmy.weixin4j.http.weixin.JsonResult; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; @@ -30,6 +32,7 @@ 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; /** @@ -57,7 +60,7 @@ public class MediaApi extends MpApi { * @param isMaterial * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(File, MediaType)} + * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(InputStream, MediaType,boolean)} * @throws WeixinException * @throws IOException */ @@ -67,28 +70,17 @@ public class MediaApi extends MpApi { if (StringUtil.isBlank(mediaTypeKey)) { mediaTypeKey = FileUtil.getFileType(file); } - MediaType mediaType = MediaType.getMediaType(mediaTypeKey); - return uploadMedia(file, mediaType, isMaterial); - } - - /** - * 上传媒体文件 此接口只包含图片、语音、缩略图三种媒体类型的上传 - * - * @param file - * 文件对象 - * @param mediaType - * 媒体类型 (image)、语音(voice)和缩略图(thumb) - * @param isMaterial - * 是否永久上传 - * @return 上传到微信服务器返回的媒体标识 - * @throws WeixinException - * @see com.foxinmy.weixin4j.type.MediaType - * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#uploadMedia(String, byte[],String,boolean)} - */ - public String uploadMedia(File file, MediaType mediaType, boolean isMaterial) - throws WeixinException, IOException { - byte[] datas = IOUtil.toByteArray(new FileInputStream(file)); - return uploadMedia(file.getName(), datas, mediaType.name(), isMaterial); + MediaType mediaType = null; + if ("bmp/png/jpeg/jpg/gif".contains(mediaTypeKey)) { + mediaType = MediaType.image; + } else if ("amr/mp3".contains(mediaTypeKey)) { + mediaType = MediaType.voice; + } else if ("mp3/wma/wav/amr".equals(mediaTypeKey)) { + mediaType = MediaType.video; + } else { + throw new WeixinException("unknown mediaType:" + mediaTypeKey); + } + return uploadMedia(new FileInputStream(file), mediaType, isMaterial); } /** @@ -98,10 +90,8 @@ public class MediaApi extends MpApi { * 否则抛出异常. * * - * @param fileName - * 文件名 - * @param bytes - * 媒体数据包 + * @param is + * 媒体数据流 * @param mediaType * 媒体文件类型:分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb) * @param isMaterial @@ -111,37 +101,45 @@ public class MediaApi extends MpApi { * href="http://mp.weixin.qq.com/wiki/5/963fc70b80dc75483a271298a76a8d59.html">上传临时素材 * @see 上传永久素材 + * @see com.foxinmy.weixin4j.type.MediaType + * @see com.foxinmy.weixin4j.mp.api.MediaApi * @throws WeixinException */ - public String uploadMedia(String fileName, byte[] bytes, String mediaType, + public String uploadMedia(InputStream is, MediaType mediaType, boolean isMaterial) throws WeixinException { - if (",image,voice,video,thumb,".indexOf(String - .format(",%s,", mediaType)) < 0) { - throw new WeixinException(String.format( - "unsupported media type:%s", mediaType)); - } if (mediaType.equals(MediaType.video.name()) && isMaterial) { throw new WeixinException( "please invoke uploadMaterialVideo method"); } Token token = tokenHolder.getToken(); WeixinResponse response = null; - if (isMaterial) { - String material_media_upload_uri = getRequestUri("material_media_upload_uri"); - try { - response = weixinClient.post(String.format( - material_media_upload_uri, token.getAccessToken()), - new FormBodyPart("media", new ByteArrayBody(bytes, - fileName)), new FormBodyPart("type", - new StringBody(mediaType, Consts.UTF_8))); - } catch (UnsupportedEncodingException e) { - throw new WeixinException(e); // ignore + try { + if (isMaterial) { + String material_media_upload_uri = getRequestUri("material_media_upload_uri"); + response = weixinClient.post( + String.format(material_media_upload_uri, + token.getAccessToken()), + new FormBodyPart("media", new InputStreamBody(is, + mediaType.getContentType().getMimeType(), + ObjectId.get().toHexString())), + 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()))); + } + } catch (UnsupportedEncodingException e) { + ; // ignore + } finally { + try { + is.close(); + } catch (IOException e) { + ; } - } else { - String file_upload_uri = getRequestUri("file_upload_uri"); - response = weixinClient.post(String.format(file_upload_uri, - token.getAccessToken(), mediaType), new FormBodyPart( - "media", new ByteArrayBody(bytes, fileName))); } return response.getAsJson().getString("media_id"); } @@ -154,27 +152,18 @@ public class MediaApi extends MpApi { * * @param mediaId * 存储在微信服务器上的媒体标识 - * @param mediaType - * 媒体文件类型:分别有图片(image)、语音(voice)、视频(video)和缩略图(thumb) - * @return 写入硬盘后的文件对象 + * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @throws WeixinException * @see 下载临时媒体文件 * @see 下载永久媒体素材 - * @see com.foxinmy.weixin4j.type.MediaType * @see {@link com.foxinmy.weixin4j.mp.api.MediaApi#downloadMedia(String,boolean)} */ - public File downloadMedia(String mediaId, MediaType mediaType, - boolean isMaterial) throws WeixinException { - if (",image,voice,video,thumb,".indexOf(String.format(",%s,", - mediaType.name())) < 0) { - throw new WeixinException(String.format( - "unsupported media type:%s", mediaType.name())); - } + public File downloadMediaFile(String mediaId, boolean isMaterial) + throws WeixinException { String media_path = ConfigUtil.getValue("media_path"); - File file = new File(media_path + File.separator + mediaId + "." - + mediaType.getFormatName()); + File file = new File(media_path + File.separator + mediaId); if (file.exists()) { return file; } @@ -195,7 +184,7 @@ public class MediaApi extends MpApi { if (os != null) { os.close(); } - } catch (IOException ignore) { + } catch (IOException e) { ; } } 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 80c84b8f..ca115f97 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 @@ -17,7 +17,6 @@ import com.foxinmy.weixin4j.tuple.Image; import com.foxinmy.weixin4j.tuple.MpArticle; import com.foxinmy.weixin4j.tuple.Text; import com.foxinmy.weixin4j.tuple.Video; -import com.foxinmy.weixin4j.type.MediaType; /** * 群发消息 @@ -42,7 +41,7 @@ public class MassTest extends TokenTest { public void uploadArticle() throws IOException, WeixinException { List@@ -241,19 +223,20 @@ public class WeixinProxy { * 否则抛出异常. *
* - * @param bytes - * 媒体数据包 + * @param is + * 媒体数据流 * @param mediaType * 媒体类型 - * @return 上传到微信服务器返回的媒体标识 * @see com.foxinmy.weixin4j.qy.api.MediaApi + * @see com.foxinmy.weixin4j.type.MediaType + * @return 上传到微信服务器返回的媒体标识 * @see 上传媒体文件说明 * @throws WeixinException */ - public String uploadMedia(String fileName, byte[] bytes, String mediaType) + public String uploadMedia(InputStream is, MediaType mediaType) throws WeixinException { - return mediaApi.uploadMedia(fileName, bytes, mediaType); + return mediaApi.uploadMedia(is, mediaType); } /** @@ -279,9 +262,7 @@ public class WeixinProxy { * * @param mediaId * 存储在微信服务器上的媒体标识 - * @param extension - * 媒体后缀名 - * @return 写入硬盘后的文件对象 + * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @throws WeixinException * @throws IOException * @see com.foxinmy.weixin4j.qy.api.MediaApi @@ -290,9 +271,8 @@ public class WeixinProxy { * @see com.foxinmy.weixin4j.type.MediaType * @see {@link com.foxinmy.weixin4j.WeixinProxy.MediaApi#downloadMedia(String)} */ - public File downloadMedia(String mediaId, String extension) - throws WeixinException { - return mediaApi.downloadMedia(mediaId, extension); + public File downloadMediaFile(String mediaId) throws WeixinException { + return mediaApi.downloadMediaFile(mediaId); } /** @@ -406,7 +386,8 @@ public class WeixinProxy { * @return 处理结果 * @throws WeixinException */ - public JsonResult createUser(User user, File avatar) throws WeixinException { + public JsonResult createUser(User user, InputStream avatar) + throws WeixinException { return userApi.createUser(user, avatar); } @@ -440,7 +421,8 @@ public class WeixinProxy { * @return 处理结果 * @throws WeixinException */ - public JsonResult updateUser(User user, File avatar) throws WeixinException { + public JsonResult updateUser(User user, InputStream avatar) + throws WeixinException { return userApi.updateUser(user, avatar); } 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 63802602..b3074429 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 @@ -1,9 +1,11 @@ package com.foxinmy.weixin4j.qy.api; +import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.io.OutputStream; import java.io.StringWriter; import java.util.LinkedHashMap; @@ -15,8 +17,8 @@ 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.apache.ByteArrayBody; import com.foxinmy.weixin4j.http.apache.FormBodyPart; +import com.foxinmy.weixin4j.http.apache.InputStreamBody; import com.foxinmy.weixin4j.http.weixin.WeixinResponse; import com.foxinmy.weixin4j.model.Consts; import com.foxinmy.weixin4j.model.Token; @@ -28,6 +30,7 @@ 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; /** @@ -55,7 +58,7 @@ public class MediaApi extends QyApi { * @param file * 媒体对象 * @return 上传到微信服务器返回的媒体标识 - * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#uploadMedia(File, MediaType)} + * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#uploadMedia(InputStream, MediaType)} * @throws WeixinException * @throws IOException */ @@ -64,27 +67,17 @@ public class MediaApi extends QyApi { if (StringUtil.isBlank(mediaTypeKey)) { mediaTypeKey = FileUtil.getFileType(file); } - MediaType mediaType = MediaType.getMediaType(mediaTypeKey); - return uploadMedia(file, mediaType); - } - - /** - * 上传媒体文件 - * - * @param file - * 文件对象 - * @param mediaType - * 媒体类型 - * @return 上传到微信服务器返回的媒体标识 - * @throws WeixinException - * @throws IOException - * @see com.foxinmy.weixin4j.type.MediaType - * @see {@link com.foxinmy.weixin4j.qy.api.MediaApi#uploadMedia(String, byte[],String)} - */ - public String uploadMedia(File file, MediaType mediaType) - throws WeixinException, IOException { - byte[] datas = IOUtil.toByteArray(new FileInputStream(file)); - return uploadMedia(file.getName(), datas, mediaType.name()); + MediaType mediaType = null; + if (mediaTypeKey.equals("jpg")) { + mediaType = MediaType.image; + } else if ("amr/mp3".contains(mediaTypeKey)) { + mediaType = MediaType.voice; + } else if (mediaTypeKey.equals("mp4")) { + mediaType = MediaType.video; + } else { + mediaType = MediaType.file; + } + return uploadMedia(new FileInputStream(file), mediaType); } /** @@ -94,8 +87,8 @@ public class MediaApi extends QyApi { * 否则抛出异常. * * - * @param bytes - * 媒体数据包 + * @param is + * 媒体数据流 * @param mediaType * 媒体类型 * @return 上传到微信服务器返回的媒体标识 @@ -103,14 +96,25 @@ public class MediaApi extends QyApi { * 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">上传媒体文件说明 * @throws WeixinException */ - public String uploadMedia(String fileName, byte[] bytes, String mediaType) + public String uploadMedia(InputStream is, MediaType mediaType) throws WeixinException { - Token token = tokenHolder.getToken(); String file_upload_uri = getRequestUri("file_upload_uri"); - WeixinResponse response = weixinClient.post(String.format(file_upload_uri, - token.getAccessToken(), mediaType), new FormBodyPart("media", - new ByteArrayBody(bytes, fileName))); - + Token token = tokenHolder.getToken(); + if (mediaType == null || mediaType == MediaType.news) { + mediaType = MediaType.file; + } else if (mediaType == MediaType.thumb) { + mediaType = MediaType.image; + } + 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) { + ; + } return response.getAsJson().getString("media_id"); } @@ -122,9 +126,7 @@ public class MediaApi extends QyApi { * * @param mediaId * 存储在微信服务器上的媒体标识 - * @param extension - * 媒体后缀名 - * @return 写入硬盘后的文件对象 + * @return 写入硬盘后的文件对象,存储路径见weixin4j.properties配置 * @throws WeixinException * @throws IOException * @see