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: + *

+ * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + *
ObjectID layout
01234567891011
timemachinepidinc
+ * + *

+ * Instances of this class are immutable. + *

+ * + * @mongodb.driver.manual core/object-id ObjectId + */ +public class ObjectId implements Comparable, java.io.Serializable { + + private static final long serialVersionUID = -4415279469780082174L; + + static final Logger LOGGER = Logger.getLogger("org.bson.ObjectId"); + + /** + * Gets a new object id. + * + * @return the new id + */ + public static ObjectId get() { + return new ObjectId(); + } + + /** + * Checks if a string could be an {@code ObjectId}. + * + * @param s + * a potential ObjectId as a String. + * @return whether the string could be an object id + * @throws IllegalArgumentException + * if hexString is null + */ + public static boolean isValid(String s) { + if (s == null) + return false; + + final int len = s.length(); + if (len != 24) + return false; + + for (int i = 0; i < len; i++) { + char c = s.charAt(i); + if (c >= '0' && c <= '9') + continue; + if (c >= 'a' && c <= 'f') + continue; + if (c >= 'A' && c <= 'F') + continue; + + return false; + } + + return true; + } + + /** + * Constructs an ObjectId given its 12-byte binary representation. + * + * @param b + * a byte array of length 12 + */ + public ObjectId(byte[] b) { + if (b.length != 12) + throw new IllegalArgumentException("need 12 bytes"); + ByteBuffer bb = ByteBuffer.wrap(b); + _time = bb.getInt(); + _machine = bb.getInt(); + _inc = bb.getInt(); + _new = false; + } + + /** + * Create a new object id. + */ + public ObjectId() { + _time = (int) (System.currentTimeMillis() / 1000); + _machine = _genmachine; + _inc = _nextInc.getAndIncrement(); + _new = true; + } + + @Override + public int hashCode() { + int x = _time; + x += (_machine * 111); + x += (_inc * 17); + return x; + } + + @Override + public boolean equals(Object o) { + if (this == o) + return true; + + ObjectId other = (ObjectId) o; + if (other == null) + return false; + + return _time == other._time && _machine == other._machine + && _inc == other._inc; + } + + /** + * Converts this instance into a 24-byte hexadecimal string representation. + * + * @return a string representation of the ObjectId in hexadecimal format + */ + public String toHexString() { + final StringBuilder buf = new StringBuilder(24); + + for (final byte b : toByteArray()) { + buf.append(String.format("%02x", b & 0xff)); + } + + return buf.toString(); + } + + /** + * Convert to a byte array. Note that the numbers are stored in big-endian + * order. + * + * @return the byte array + */ + public byte[] toByteArray() { + byte b[] = new byte[12]; + ByteBuffer bb = ByteBuffer.wrap(b); + // by default BB is big endian like we need + bb.putInt(_time); + bb.putInt(_machine); + bb.putInt(_inc); + return b; + } + + static String _pos(String s, int p) { + return s.substring(p * 2, (p * 2) + 2); + } + + public String toString() { + byte b[] = toByteArray(); + + StringBuilder buf = new StringBuilder(24); + + for (int i = 0; i < b.length; i++) { + int x = b[i] & 0xFF; + String s = Integer.toHexString(x); + if (s.length() == 1) + buf.append("0"); + buf.append(s); + } + + return buf.toString(); + } + + int _compareUnsigned(int i, int j) { + long li = 0xFFFFFFFFL; + li = i & li; + long lj = 0xFFFFFFFFL; + lj = j & lj; + long diff = li - lj; + if (diff < Integer.MIN_VALUE) + return Integer.MIN_VALUE; + if (diff > Integer.MAX_VALUE) + return Integer.MAX_VALUE; + return (int) diff; + } + + public int compareTo(ObjectId id) { + if (id == null) + return -1; + + int x = _compareUnsigned(_time, id._time); + if (x != 0) + return x; + + x = _compareUnsigned(_machine, id._machine); + if (x != 0) + return x; + + return _compareUnsigned(_inc, id._inc); + } + + /** + * Gets the timestamp (number of seconds since the Unix epoch). + * + * @return the timestamp + */ + public int getTimestamp() { + return _time; + } + + /** + * Gets the timestamp as a {@code Date} instance. + * + * @return the Date + */ + public Date getDate() { + return new Date(_time * 1000L); + } + + /** + * Gets the current value of the auto-incrementing counter. + * + * @return the current counter value. + */ + public static int getCurrentCounter() { + return _nextInc.get(); + } + + final int _time; + final int _machine; + final int _inc; + + boolean _new; + + private static AtomicInteger _nextInc = new AtomicInteger( + (new java.util.Random()).nextInt()); + + private static final int _genmachine; + static { + + try { + // build a 2-byte machine piece based on NICs info + int machinePiece; + { + try { + StringBuilder sb = new StringBuilder(); + Enumeration e = NetworkInterface + .getNetworkInterfaces(); + while (e.hasMoreElements()) { + NetworkInterface ni = e.nextElement(); + sb.append(ni.toString()); + } + machinePiece = sb.toString().hashCode() << 16; + } catch (Throwable e) { + // exception sometimes happens with IBM JVM, use random + LOGGER.log(Level.WARNING, e.getMessage(), e); + machinePiece = (new Random().nextInt()) << 16; + } + LOGGER.fine("machine piece post: " + + Integer.toHexString(machinePiece)); + } + + // add a 2 byte process piece. It must represent not only the JVM + // but the class loader. + // Since static var belong to class loader there could be collisions + // otherwise + final int processPiece; + { + int processId = new java.util.Random().nextInt(); + try { + processId = java.lang.management.ManagementFactory + .getRuntimeMXBean().getName().hashCode(); + } catch (Throwable t) { + } + + ClassLoader loader = ObjectId.class.getClassLoader(); + int loaderId = loader != null + ? System.identityHashCode(loader) + : 0; + + StringBuilder sb = new StringBuilder(); + sb.append(Integer.toHexString(processId)); + sb.append(Integer.toHexString(loaderId)); + processPiece = sb.toString().hashCode() & 0xFFFF; + LOGGER.fine("process piece: " + + Integer.toHexString(processPiece)); + } + + _genmachine = machinePiece | processPiece; + LOGGER.fine("machine : " + Integer.toHexString(_genmachine)); + } catch (Exception e) { + throw new RuntimeException(e); + } + + } +} diff --git a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java index a890ab39..1d05bfb5 100644 --- a/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java +++ b/weixin4j-mp/src/main/java/com/foxinmy/weixin4j/mp/WeixinProxy.java @@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.mp; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.Date; import java.util.List; @@ -132,7 +133,8 @@ public class WeixinProxy { * @param isMaterial * 是否永久上传 * @return 上传到微信服务器返回的媒体标识 - * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#uploadMedia(File, MediaType)} + * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#uploadMedia(InputStream, MediaType,boolean)} + * @see com.foxinmy.weixin4j.mp.api.MediaApi * @throws WeixinException * @throws IOException */ @@ -142,49 +144,30 @@ public class WeixinProxy { } /** - * 上传媒体文件 - * - * @param file - * 文件对象 - * @param mediaType - * 媒体类型 - * @param isMaterial - * 是否永久上传 - * @return 上传到微信服务器返回的媒体标识 - * @throws WeixinException - * @throws IOException - * @see com.foxinmy.weixin4j.type.MediaType - * @see {@link com.foxinmy.weixin4j.mp.WeixinProxy#uploadMedia(String, byte[],String)} - */ - public String uploadMedia(File file, MediaType mediaType, boolean isMaterial) - throws WeixinException, IOException { - return mediaApi.uploadMedia(file, mediaType, isMaterial); - } - - /** - * 上传媒体文件 + * 上传媒体文件
此接口只包含图片、语音、缩略图、视频(临时)四种媒体类型的上传 *

* 正常情况下返回{"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 articles = new ArrayList(); String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), - MediaType.image, false); + false); articles.add(new MpArticle(thumbMediaId, "title", "content")); massApi.uploadArticle(articles); } @@ -71,7 +70,7 @@ public class MassTest extends TokenTest { public void massArticleByGroup() throws IOException, WeixinException { List articles = new ArrayList(); String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), - MediaType.image, false); + false); articles.add(new MpArticle(thumbMediaId, "title", "content")); String massId = massApi.massArticleByGroupId(articles, 0); Assert.assertTrue(massId != null); @@ -81,7 +80,7 @@ public class MassTest extends TokenTest { public void massArticleByOpenIds() throws IOException, WeixinException { List articles = new ArrayList(); String thumbMediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), - MediaType.image, false); + false); articles.add(new MpArticle(thumbMediaId, "title", "content")); String massId = massApi.massArticleByOpenIds(articles, "owGBft_vbBbOaQOmpEUE4xDLeRSU"); diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java index c6cfef76..9c0c09d1 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/MediaTest.java @@ -39,7 +39,7 @@ public class MediaTest extends TokenTest { @Test public void upload1() throws IOException, WeixinException { File file = new File("/Users/jy/Downloads/weixin4j.png"); - String mediaId = mediaApi.uploadMedia(file, MediaType.image, false); + String mediaId = mediaApi.uploadMedia(file, false); // 1Vgd1R5DdznSc3rPxd-sNZ3pLt54cejhJ5ItuNcCgrqoQArNANWy5oxso_r9KNlE Assert.assertNotNull(mediaId); System.err.println(mediaId); @@ -48,16 +48,16 @@ public class MediaTest extends TokenTest { @Test public void download1() throws WeixinException, IOException { File file = mediaApi - .downloadMedia( + .downloadMediaFile( "1Vgd1R5DdznSc3rPxd-sNZ3pLt54cejhJ5ItuNcCgrqoQArNANWy5oxso_r9KNlE", - MediaType.image, false); + false); Assert.assertTrue(file.exists()); } @Test public void upload2() throws IOException, WeixinException { File file = new File("/Users/jy/Downloads/test.jpg"); - String mediaId = mediaApi.uploadMedia(file, MediaType.image, true); + String mediaId = mediaApi.uploadMedia(file, true); // 8790403529 Assert.assertNotNull(mediaId); System.err.println(mediaId); @@ -85,7 +85,7 @@ public class MediaTest extends TokenTest { @Test public void download2() throws WeixinException, IOException { - File file = mediaApi.downloadMedia("8790403529", MediaType.image, true); + File file = mediaApi.downloadMediaFile("8790403529", true); Assert.assertTrue(file.exists()); } @@ -129,10 +129,11 @@ public class MediaTest extends TokenTest { 20); System.err.println(mediaRecord); } - + @Test public void listAllMaterialMedia() throws WeixinException { - List mediaList = mediaApi.listAllMaterialMedia(MediaType.image); + List mediaList = mediaApi + .listAllMaterialMedia(MediaType.image); System.err.println(mediaList); } } diff --git a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/NotifyTest.java b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/NotifyTest.java index 7b4d80db..babe6173 100644 --- a/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/NotifyTest.java +++ b/weixin4j-mp/src/test/java/com/foxinmy/weixin4j/mp/test/NotifyTest.java @@ -18,7 +18,6 @@ import com.foxinmy.weixin4j.tuple.News; import com.foxinmy.weixin4j.tuple.Text; import com.foxinmy.weixin4j.tuple.Video; import com.foxinmy.weixin4j.tuple.Voice; -import com.foxinmy.weixin4j.type.MediaType; /** * 客服消息测试 @@ -90,8 +89,7 @@ public class NotifyTest extends TokenTest { @Test public void send2() throws WeixinException, IOException { - String mediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), - MediaType.image, false); + String mediaId = mediaApi.uploadMedia(new File("/tmp/test.jpg"), false); NotifyMessage imageNotify = new NotifyMessage( "owGBft_vbBbOaQOmpEUE4xDLeRSU", new Image(mediaId)); JsonResult result = notifyApi.sendNotify(imageNotify); diff --git a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java index 1a287f4f..b71042c2 100644 --- a/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java +++ b/weixin4j-qy/src/main/java/com/foxinmy/weixin4j/qy/WeixinProxy.java @@ -2,6 +2,7 @@ package com.foxinmy.weixin4j.qy; import java.io.File; import java.io.IOException; +import java.io.InputStream; import java.util.List; import com.alibaba.fastjson.JSONObject; @@ -207,7 +208,7 @@ public class WeixinProxy { * 媒体对象 * @return 上传到微信服务器返回的媒体标识 * @see com.foxinmy.weixin4j.qy.api.MediaApi - * @see {@link com.foxinmy.weixin4j.qy.WeixinProxy.MediaApi#uploadMedia(File, MediaType)} + * @see {@link com.foxinmy.weixin4j.qy.WeixinProxy.MediaApi#uploadMedia(InputStream, MediaType)} * @throws WeixinException * @throws IOException */ @@ -215,25 +216,6 @@ public class WeixinProxy { return mediaApi.uploadMedia(file); } - /** - * 上传媒体文件 - * - * @param file - * 文件对象 - * @param mediaType - * 媒体类型 - * @return 上传到微信服务器返回的媒体标识 - * @throws WeixinException - * @throws IOException - * @see com.foxinmy.weixin4j.qy.api.MediaApi - * @see com.foxinmy.weixin4j.type.MediaType - * @see {@link com.foxinmy.weixin4j.qy.WeixinProxy#uploadMedia(String, byte[],String)} - */ - public String uploadMedia(File file, MediaType mediaType) - throws WeixinException, IOException { - return mediaApi.uploadMedia(file, mediaType); - } - /** * 上传媒体文件(完全公开。所有管理员均可调用,media_id可以共享) *

@@ -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