Skip to content

Commit

Permalink
Merge pull request #518 from qiniu/ys_dev
Browse files Browse the repository at this point in the history
支持构建 Download url & 基础 api 支持流姿势上传
  • Loading branch information
Mei-Zhao authored Apr 29, 2021
2 parents 74ab710 + ad30ab4 commit adce452
Show file tree
Hide file tree
Showing 20 changed files with 831 additions and 54 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
# Changelog
## 7.5.1 (2021-04-29)

## 增加
* 上传服务基础上传数据 api 支持 InputStream
* 支持构建 DownloadUrl 功能


## 7.5.0 (2021-04-15)

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/qiniu/common/Constants.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ public final class Constants {
/**
* 版本号
*/
public static final String VERSION = "7.5.0";
public static final String VERSION = "7.5.1";
/**
* 块大小,不能改变
*/
Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/qiniu/http/Client.java
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,12 @@ public Response post(String url, byte[] body, int offset, int size,
return post(url, rbody, headers);
}

private Response post(String url, RequestBody body, StringMap headers) throws QiniuException {
public Response post(String url, RequestBody body, StringMap headers) throws QiniuException {
Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
return send(requestBuilder, headers);
}

private Response put(String url, RequestBody body, StringMap headers) throws QiniuException {
public Response put(String url, RequestBody body, StringMap headers) throws QiniuException {
Request.Builder requestBuilder = new Request.Builder().url(url).put(body);
return send(requestBuilder, headers);
}
Expand Down
94 changes: 94 additions & 0 deletions src/main/java/com/qiniu/http/RequestStreamBody.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.qiniu.http;

import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.BufferedSink;
import okio.Okio;
import okio.Source;

import java.io.EOFException;
import java.io.IOException;
import java.io.InputStream;

public class RequestStreamBody extends RequestBody {

private long limitSize = -1;
private long sinkSize = 1024 * 100;
private final MediaType type;
private final InputStream stream;

/**
* 构造函数
*
* @param stream 请求数据流
* @param contentType 请求数据类型
*/
public RequestStreamBody(InputStream stream, String contentType) {
this.stream = stream;
this.type = MediaType.parse(contentType);
}

/**
* 构造函数
*
* @param stream 请求数据流
* @param contentType 请求数据类型
*/
public RequestStreamBody(InputStream stream, MediaType contentType) {
this.stream = stream;
this.type = contentType;
}

/**
* 构造函数
*
* @param stream 请求数据流
* @param contentType 请求数据类型
* @param limitSize 最大读取 stream 的大小;为 -1 时不限制读取所有
*/
public RequestStreamBody(InputStream stream, MediaType contentType, long limitSize) {
this.stream = stream;
this.type = contentType;
this.limitSize = limitSize;
}

/**
* 配置请求时,每次从流中读取的数据大小
*
* @param sinkSize 每次从流中读取的数据大小
* @return RequestStreamBody
* @see RequestStreamBody#writeTo(BufferedSink)
*/
public RequestStreamBody setSinkSize(long sinkSize) {
if (sinkSize > 0) {
this.sinkSize = sinkSize;
}
return this;
}

@Override
public MediaType contentType() {
return type;
}

@Override
public void writeTo(BufferedSink sink) throws IOException {
try (Source source = Okio.source(stream)) {
int offset = 0;
while (limitSize < 0 || offset < limitSize) {
long byteSize = sinkSize;
if (offset < limitSize) {
byteSize = Math.min(sinkSize, limitSize - offset);
}

try {
sink.write(source, byteSize);
sink.flush();
offset += byteSize;
} catch (EOFException e) {
break;
}
}
}
}
}
4 changes: 4 additions & 0 deletions src/main/java/com/qiniu/http/Response.java
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ public String contentType() {
return ctype(response);
}

public String header(String name, String defaultValue) {
return response.header(name, defaultValue);
}

public boolean isJson() {
return contentType().equals(Client.JsonMime);
}
Expand Down
6 changes: 6 additions & 0 deletions src/main/java/com/qiniu/processing/OperationManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public OperationManager(Auth auth, Client client) {
this.configuration = new Configuration();
}

public OperationManager(Auth auth, Configuration cfg, Client client) {
this.auth = auth;
this.client = client;
this.configuration = cfg;
}

/**
* 发送请求对空间中的文件进行持久化处理
*
Expand Down
98 changes: 69 additions & 29 deletions src/main/java/com/qiniu/storage/Api.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,14 @@
import com.qiniu.common.QiniuException;
import com.qiniu.http.Client;
import com.qiniu.http.MethodType;
import com.qiniu.http.RequestStreamBody;
import com.qiniu.util.StringMap;
import com.qiniu.util.StringUtils;
import okhttp3.MediaType;
import okhttp3.RequestBody;
import okio.BufferedSink;

import java.io.InputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.*;
Expand Down Expand Up @@ -35,14 +40,11 @@ protected com.qiniu.http.Response requestByClient(Request request) throws QiniuE
if (request.method == MethodType.GET) {
return client.get(request.getUrl().toString(), request.getHeader());
} else if (request.method == MethodType.POST) {
return client.post(request.getUrl().toString(), request.body, request.bodyOffset, request.bodySize,
request.getHeader(), request.bodyContentType);
return client.post(request.getUrl().toString(), request.getRequestBody(), request.getHeader());
} else if (request.method == MethodType.PUT) {
return client.put(request.getUrl().toString(), request.body, request.bodyOffset, request.bodySize,
request.getHeader(), request.bodyContentType);
return client.put(request.getUrl().toString(), request.getRequestBody(), request.getHeader());
} else if (request.method == MethodType.DELETE) {
return client.delete(request.getUrl().toString(), request.body, request.bodyOffset, request.bodySize,
request.getHeader(), request.bodyContentType);
return client.delete(request.getUrl().toString(), request.getRequestBody(), request.getHeader());
} else {
throw QiniuException.unrecoverable("暂不支持这种请求方式");
}
Expand Down Expand Up @@ -91,12 +93,14 @@ public static class Request {
private final Map<String, String> header = new HashMap<>();

/**
* 请求数据是在 body 中,从 bodyOffset 开始,获取 bodySize 大小的数据
* 请求 body
*/
private byte[] body = new byte[0];
private int bodySize = 0;
private int bodyOffset = 0;
private String bodyContentType = Client.DefaultMime;
private RequestBody body;
/**
* 请求时,每次从流中读取的数据大小
* 注: body 使用 InputStream 时才有效
*/
private long streamBodySinkSize = 1024 * 10;

/**
* 构造请求对象
Expand Down Expand Up @@ -174,7 +178,7 @@ protected void buildPath() throws QiniuException {
* @param value value
*/
protected void addQueryPair(String key, String value) {
if (StringUtils.isNullOrEmpty(key) || value == null) {
if (StringUtils.isNullOrEmpty(key)) {
return;
}
queryPairs.add(new Pair<String, String>(key, value));
Expand Down Expand Up @@ -237,7 +241,7 @@ protected void setMethod(MethodType method) {
* @param key key
* @param value value
*/
protected void addHeaderField(String key, String value) {
public void addHeaderField(String key, String value) {
if (StringUtils.isNullOrEmpty(key) || StringUtils.isNullOrEmpty(value)) {
return;
}
Expand Down Expand Up @@ -292,16 +296,59 @@ public URL getUrl() throws QiniuException {
* @param contentType 请求数据类型
*/
protected void setBody(byte[] body, int offset, int size, String contentType) {
this.body = body;
this.bodyOffset = offset;
this.bodySize = size;
if (!StringUtils.isNullOrEmpty(contentType)) {
this.bodyContentType = contentType;
if (StringUtils.isNullOrEmpty(contentType)) {
contentType = Client.DefaultMime;
}
MediaType type = MediaType.parse(contentType);
this.body = RequestBody.create(type, body, offset, size);
}

/**
* 设置请求体
*
* @param body 请求数据源
* @param contentType 请求数据类型
* @param limitSize 最大读取 body 的大小;body 有多余则被舍弃;body 不足则会上传多有 body;
* 如果提前不知道 body 大小,但想上传所有 body,limitSize 设置为 -1 即可;
*/
protected void setBody(InputStream body, String contentType, long limitSize) {
if (StringUtils.isNullOrEmpty(contentType)) {
contentType = Client.DefaultMime;
}
MediaType type = MediaType.parse(contentType);
this.body = new RequestStreamBody(body, type, limitSize);
}

/**
* 使用 streamBody 时,每次读取 streamBody 的大小,读取后发送
* 默认:{@link Api.Request#streamBodySinkSize}
* 相关:{@link RequestStreamBody#writeTo(BufferedSink) sinkSize}
*
* @param streamBodySinkSize 每次读取 streamBody 的大小
*/
public Request setStreamBodySinkSize(long streamBodySinkSize) {
this.streamBodySinkSize = streamBodySinkSize;
return this;
}

/**
* 是否有请求体
*
* @return 是否有请求体
*/
public boolean hasBody() {
return body != null && body.length > 0 && bodySize > 0;
return body != null;
}

private RequestBody getRequestBody() {
if (hasBody()) {
if (body instanceof RequestStreamBody) {
((RequestStreamBody) body).setSinkSize(streamBodySinkSize);
}
return body;
} else {
return RequestBody.create(null, new byte[0]);
}
}

/**
Expand All @@ -310,11 +357,7 @@ public boolean hasBody() {
* @throws QiniuException
*/
protected void buildBodyInfo() throws QiniuException {
if (body == null) {
body = new byte[0];
bodySize = 0;
bodyOffset = 0;
}

}

/**
Expand All @@ -328,10 +371,7 @@ protected void prepareToRequest() throws QiniuException {
buildBodyInfo();
}

void test() {
}

private static class Pair<K, V> {
protected static class Pair<K, V> {

/**
* Key of this <code>Pair</code>.
Expand Down Expand Up @@ -367,7 +407,7 @@ V getValue() {
* @param key The key for this pair
* @param value The value to use for this pair
*/
Pair(K key, V value) {
protected Pair(K key, V value) {
this.key = key;
this.value = value;
}
Expand Down
28 changes: 26 additions & 2 deletions src/main/java/com/qiniu/storage/ApiUploadV1MakeBlock.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
import com.qiniu.http.Client;
import com.qiniu.http.MethodType;

import java.io.InputStream;

/**
* 分片上传 v1 版 api: 创建块
* 本接口用于为后续分片上传创建一个新的 block,同时上传该块第一个 chunk 数据。
Expand Down Expand Up @@ -83,8 +85,12 @@ public Request(String urlPrefix, String token, Integer blockSize) {
}

/**
* 配置块第一个上传片数据【必须】
* 配置块第一个上传片数据
* 块数据 size 必须不大于 4M,block 中所有 chunk 的 size 总和必须为 4M, SDK 内部不做 block/chunk size 检测
* 块数据:在 data 中,从 offset 开始的 size 大小的数据
* 注:
* 必须通过 {@link ApiUploadV1MakeBlock.Request#setFirstChunkData(byte[], int, int, String)} 或
* {@link ApiUploadV1MakeBlock.Request#setFirstChunkData(InputStream, String, long)} 配置块第一个上传片数据
*
* @param data 块数据源
* @param offset 块数据在 data 中的偏移量
Expand All @@ -97,6 +103,24 @@ public Request setFirstChunkData(byte[] data, int offset, int size, String conte
return this;
}

/**
* 配置块第一个上传片数据
* 块数据 size 必须不大于 4M,block 中所有 chunk 的 size 总和必须为 4M, SDK 内部不做 block/chunk size 检测
* 注:
* 必须通过 {@link ApiUploadV1MakeBlock.Request#setFirstChunkData(byte[], int, int, String)} 或
* {@link ApiUploadV1MakeBlock.Request#setFirstChunkData(InputStream, String, long)} 配置块第一个上传片数据
*
* @param data 块数据源
* @param contentType 块数据类型
* @param limitSize 最大读取 data 的大小;data 有多余则被舍弃;data 不足则会上传多有 data;
* 如果提前不知道 data 大小,但想上传所有 data,limitSize 设置为 -1 即可;
* @return Request
*/
public Request setFirstChunkData(InputStream data, String contentType, long limitSize) {
super.setBody(data, contentType, limitSize);
return this;
}

@Override
protected void buildPath() throws QiniuException {
if (blockSize == null) {
Expand All @@ -111,7 +135,7 @@ protected void buildPath() throws QiniuException {
@Override
protected void buildBodyInfo() throws QiniuException {
if (!hasBody()) {
ApiUtils.throwInvalidRequestParamException("block data");
ApiUtils.throwInvalidRequestParamException("block first chunk data");
}
}
}
Expand Down
Loading

0 comments on commit adce452

Please sign in to comment.