diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamData.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamData.java
new file mode 100644
index 000000000..fe80af11e
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/InputStreamData.java
@@ -0,0 +1,27 @@
+package me.chanjar.weixin.common.util.http;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.experimental.Accessors;
+
+import java.io.InputStream;
+import java.io.Serializable;
+
+/**
+ * 输入流数据.
+ *
+ * InputStreamData
+ *
+ * @author zichuan.zhou91@gmail.com
+ * @date 2022/2/15
+ */
+@Data
+@Accessors(chain = true)
+@NoArgsConstructor
+@AllArgsConstructor
+public class InputStreamData implements Serializable {
+ private static final long serialVersionUID = -4627006604779378520L;
+ private InputStream inputStream;
+ private String filename;
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java
new file mode 100644
index 000000000..de4be2170
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/MediaInputStreamUploadRequestExecutor.java
@@ -0,0 +1,43 @@
+package me.chanjar.weixin.common.util.http;
+
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.apache.ApacheMediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.jodd.JoddHttpMediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.okhttp.OkHttpMediaInputStreamUploadRequestExecutor;
+
+import java.io.IOException;
+
+/**
+ * 上传媒体文件请求执行器.
+ * 请求的参数是File, 返回的结果是String
+ *
+ * @author Daniel Qian
+ */
+public abstract class MediaInputStreamUploadRequestExecutor implements RequestExecutor {
+ protected RequestHttp requestHttp;
+
+ public MediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ this.requestHttp = requestHttp;
+ }
+
+ @Override
+ public void execute(String uri, InputStreamData data, ResponseHandler handler, WxType wxType) throws WxErrorException, IOException {
+ handler.handle(this.execute(uri, data, wxType));
+ }
+
+ public static RequestExecutor create(RequestHttp requestHttp) {
+ switch (requestHttp.getRequestType()) {
+ case APACHE_HTTP:
+ return new ApacheMediaInputStreamUploadRequestExecutor(requestHttp);
+ case JODD_HTTP:
+ return new JoddHttpMediaInputStreamUploadRequestExecutor(requestHttp);
+ case OK_HTTP:
+ return new OkHttpMediaInputStreamUploadRequestExecutor(requestHttp);
+ default:
+ return null;
+ }
+ }
+
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java
index da1292ba6..b5e394756 100644
--- a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/RequestExecutor.java
@@ -37,4 +37,6 @@ public interface RequestExecutor {
* @throws IOException io异常
*/
void execute(String uri, E data, ResponseHandler handler, WxType wxType) throws WxErrorException, IOException;
+
+
}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java
new file mode 100644
index 000000000..3e6d189e8
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/apache/ApacheMediaInputStreamUploadRequestExecutor.java
@@ -0,0 +1,59 @@
+package me.chanjar.weixin.common.util.http.apache;
+
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.InputStreamData;
+import me.chanjar.weixin.common.util.http.MediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import org.apache.http.HttpEntity;
+import org.apache.http.HttpHost;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpPost;
+import org.apache.http.entity.ContentType;
+import org.apache.http.entity.mime.HttpMultipartMode;
+import org.apache.http.entity.mime.MultipartEntityBuilder;
+import org.apache.http.impl.client.CloseableHttpClient;
+
+import java.io.IOException;
+
+/**
+ * 文件输入流上传.
+ *
+ * @author meiqin.zhou91@gmail.com
+ * @date 2022/02/15
+ */
+public class ApacheMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor {
+ public ApacheMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public WxMediaUploadResult execute(String uri, InputStreamData data, WxType wxType) throws WxErrorException, IOException {
+ HttpPost httpPost = new HttpPost(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ RequestConfig config = RequestConfig.custom().setProxy(requestHttp.getRequestHttpProxy()).build();
+ httpPost.setConfig(config);
+ }
+ if (data != null) {
+ HttpEntity entity = MultipartEntityBuilder
+ .create()
+ .addBinaryBody("media", data.getInputStream(), ContentType.DEFAULT_BINARY, data.getFilename())
+ .setMode(HttpMultipartMode.RFC6532)
+ .build();
+ httpPost.setEntity(entity);
+ }
+ try (CloseableHttpResponse response = requestHttp.getRequestHttpClient().execute(httpPost)) {
+ String responseContent = Utf8ResponseHandler.INSTANCE.handleResponse(response);
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ return WxMediaUploadResult.fromJson(responseContent);
+ } finally {
+ httpPost.releaseConnection();
+ }
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java
new file mode 100644
index 000000000..d0591aee9
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/jodd/JoddHttpMediaInputStreamUploadRequestExecutor.java
@@ -0,0 +1,61 @@
+package me.chanjar.weixin.common.util.http.jodd;
+
+import jodd.http.HttpConnectionProvider;
+import jodd.http.HttpRequest;
+import jodd.http.HttpResponse;
+import jodd.http.ProxyInfo;
+import jodd.http.up.ByteArrayUploadable;
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.InputStreamData;
+import me.chanjar.weixin.common.util.http.MediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 文件输入流上传.
+ *
+ * @author meiqin.zhou91@gmail.com
+ * @date 2022/02/15
+ */
+public class JoddHttpMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor {
+ public JoddHttpMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public WxMediaUploadResult execute(String uri, InputStreamData data, WxType wxType) throws WxErrorException, IOException {
+ HttpRequest request = HttpRequest.post(uri);
+ if (requestHttp.getRequestHttpProxy() != null) {
+ requestHttp.getRequestHttpClient().useProxy(requestHttp.getRequestHttpProxy());
+ }
+ request.withConnectionProvider(requestHttp.getRequestHttpClient());
+ request.form("media", new ByteArrayUploadable(this.toByteArray(data.getInputStream()), data.getFilename()));
+ HttpResponse response = request.send();
+ response.charset(StandardCharsets.UTF_8.name());
+
+ String responseContent = response.bodyText();
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ return WxMediaUploadResult.fromJson(responseContent);
+ }
+
+ public byte[] toByteArray(InputStream input) throws IOException {
+ try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
+ byte[] buffer = new byte[4096];
+ int n = 0;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ }
+ return output.toByteArray();
+ }
+ }
+}
diff --git a/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java
new file mode 100644
index 000000000..ec85015b2
--- /dev/null
+++ b/weixin-java-common/src/main/java/me/chanjar/weixin/common/util/http/okhttp/OkHttpMediaInputStreamUploadRequestExecutor.java
@@ -0,0 +1,56 @@
+package me.chanjar.weixin.common.util.http.okhttp;
+
+import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
+import me.chanjar.weixin.common.enums.WxType;
+import me.chanjar.weixin.common.error.WxError;
+import me.chanjar.weixin.common.error.WxErrorException;
+import me.chanjar.weixin.common.util.http.InputStreamData;
+import me.chanjar.weixin.common.util.http.MediaInputStreamUploadRequestExecutor;
+import me.chanjar.weixin.common.util.http.RequestHttp;
+import okhttp3.*;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+
+/**
+ * 文件输入流上传.
+ *
+ * @author meiqin.zhou91@gmail.com
+ * @date 2022/02/15
+ */
+public class OkHttpMediaInputStreamUploadRequestExecutor extends MediaInputStreamUploadRequestExecutor {
+ public OkHttpMediaInputStreamUploadRequestExecutor(RequestHttp requestHttp) {
+ super(requestHttp);
+ }
+
+ @Override
+ public WxMediaUploadResult execute(String uri, InputStreamData data, WxType wxType) throws WxErrorException, IOException {
+
+ RequestBody body = new MultipartBody.Builder()
+ .setType(MediaType.parse("multipart/form-data"))
+ .addFormDataPart("media", data.getFilename(), RequestBody.create(this.toByteArray(data.getInputStream()), MediaType.parse("application/octet-stream")))
+ .build();
+ Request request = new Request.Builder().url(uri).post(body).build();
+
+ Response response = requestHttp.getRequestHttpClient().newCall(request).execute();
+ String responseContent = response.body().string();
+ WxError error = WxError.fromJson(responseContent, wxType);
+ if (error.getErrorCode() != 0) {
+ throw new WxErrorException(error);
+ }
+ return WxMediaUploadResult.fromJson(responseContent);
+ }
+
+
+ public byte[] toByteArray(InputStream input) throws IOException {
+ try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
+ byte[] buffer = new byte[4096];
+ int n = 0;
+ while (-1 != (n = input.read(buffer))) {
+ output.write(buffer, 0, n);
+ }
+ return output.toByteArray();
+ }
+ }
+}
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java
index a51e04e17..d9b53f250 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/WxCpMediaService.java
@@ -35,6 +35,21 @@ public interface WxCpMediaService {
WxMediaUploadResult upload(String mediaType, String fileType, InputStream inputStream)
throws WxErrorException, IOException;
+ /**
+ *
+ * 上传多媒体文件.
+ *
+ *
+ * @param mediaType 媒体类型, 请看{@link me.chanjar.weixin.common.api.WxConsts}
+ * @param filename 文件名.例如:wework.txt
+ * @param url 远程链接
+ * @return
+ * @throws WxErrorException
+ * @throws IOException
+ */
+ WxMediaUploadResult upload(String mediaType, String filename, String url)
+ throws WxErrorException, IOException;
+
/**
* 上传多媒体文件.
*
diff --git a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java
index b83b6d39a..8e88aa20e 100644
--- a/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java
+++ b/weixin-java-cp/src/main/java/me/chanjar/weixin/cp/api/impl/WxCpMediaServiceImpl.java
@@ -5,6 +5,8 @@ import me.chanjar.weixin.common.bean.result.WxMediaUploadResult;
import me.chanjar.weixin.common.error.WxErrorException;
import me.chanjar.weixin.common.util.fs.FileUtils;
import me.chanjar.weixin.common.util.http.BaseMediaDownloadRequestExecutor;
+import me.chanjar.weixin.common.util.http.InputStreamData;
+import me.chanjar.weixin.common.util.http.MediaInputStreamUploadRequestExecutor;
import me.chanjar.weixin.common.util.http.MediaUploadRequestExecutor;
import me.chanjar.weixin.cp.api.WxCpMediaService;
import me.chanjar.weixin.cp.api.WxCpService;
@@ -12,6 +14,8 @@ import me.chanjar.weixin.cp.api.WxCpService;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.URL;
import java.util.UUID;
import static me.chanjar.weixin.cp.constant.WxCpApiPathConsts.Media.*;
@@ -34,6 +38,32 @@ public class WxCpMediaServiceImpl implements WxCpMediaService {
return this.upload(mediaType, FileUtils.createTmpFile(inputStream, UUID.randomUUID().toString(), fileType));
}
+ @Override
+ public WxMediaUploadResult upload(String mediaType, String filename, String url) throws WxErrorException, IOException {
+ HttpURLConnection conn = null;
+ InputStream inputStream = null;
+ try {
+ URL remote = new URL(url);
+ conn = (HttpURLConnection) remote.openConnection();
+ //设置超时间为3秒
+ conn.setConnectTimeout(60 * 1000);
+ //防止屏蔽程序抓取而返回403错误
+ conn.setRequestProperty("User-Agent", "Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)");
+ inputStream = conn.getInputStream();
+ return this.mainService.execute(MediaInputStreamUploadRequestExecutor.create(this.mainService.getRequestHttp()), this.mainService.getWxCpConfigStorage().getApiUrl(MEDIA_UPLOAD + mediaType), new InputStreamData(inputStream, filename));
+ } finally {
+ if (inputStream != null) {
+ try {
+ inputStream.close();
+ } catch (IOException e) {
+ }
+ }
+ if (conn != null) {
+ conn.disconnect();
+ }
+ }
+ }
+
@Override
public WxMediaUploadResult upload(String mediaType, File file) throws WxErrorException {
return this.mainService.execute(MediaUploadRequestExecutor.create(this.mainService.getRequestHttp()),