├── .gitignore
├── LICENSE
├── README.md
├── pom.xml
└── src
├── main
└── java
│ └── com
│ └── qcloud
│ └── cos
│ ├── COS.java
│ ├── COSClient.java
│ ├── ClientConfig.java
│ ├── ErrorCode.java
│ ├── common_utils
│ ├── CommonCodecUtils.java
│ ├── CommonFileUtils.java
│ ├── CommonParamCheckUtils.java
│ ├── CommonPathUtils.java
│ └── CommonSha1Utils.java
│ ├── demo
│ └── Demo.java
│ ├── exception
│ ├── AbstractCosException.java
│ ├── CosExceptionType.java
│ ├── NetworkException.java
│ ├── ParamException.java
│ ├── ServerException.java
│ └── UnknownException.java
│ ├── http
│ ├── AbstractCosHttpClient.java
│ ├── DefaultCosHttpClient.java
│ ├── HttpContentType.java
│ ├── HttpMethod.java
│ ├── HttpRequest.java
│ ├── IdleConnectionMonitorThread.java
│ ├── RequestBodyKey.java
│ ├── RequestBodyValue.java
│ ├── RequestHeaderKey.java
│ ├── RequestHeaderValue.java
│ └── ResponseBodyKey.java
│ ├── meta
│ ├── COSObjectInputStream.java
│ ├── FileAuthority.java
│ ├── FileStat.java
│ ├── InsertOnly.java
│ ├── OverWrite.java
│ ├── SliceFileDataTask.java
│ ├── SlicePart.java
│ └── UploadSliceFileContext.java
│ ├── op
│ ├── BaseOp.java
│ ├── FileOp.java
│ └── FolderOp.java
│ ├── request
│ ├── AbstractBaseRequest.java
│ ├── AbstractDelRequest.java
│ ├── AbstractStatRequest.java
│ ├── CreateFolderRequest.java
│ ├── DelFileRequest.java
│ ├── DelFolderRequest.java
│ ├── GetFileInputStreamRequest.java
│ ├── GetFileLocalRequest.java
│ ├── ListFolderRequest.java
│ ├── ListPartsRequest.java
│ ├── MoveFileRequest.java
│ ├── StatFileRequest.java
│ ├── StatFolderRequest.java
│ ├── UpdateFileRequest.java
│ ├── UpdateFolderRequest.java
│ ├── UploadFileRequest.java
│ └── UploadSliceFileRequest.java
│ └── sign
│ ├── Credentials.java
│ └── Sign.java
└── test
├── java
└── com
│ └── qcloud
│ └── cos
│ └── common_utils
│ └── CommonCodecUtilsTest.java
└── resources
├── bigfile.txt
├── empty.txt
├── local_file_1.txt
├── local_file_2.txt
└── log4j.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | *.class
2 |
3 | # Mobile Tools for Java (J2ME)
4 | .mtj.tmp/
5 |
6 | # Package Files #
7 | *.jar
8 | *.war
9 | *.ear
10 |
11 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
12 | hs_err_pid*
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # tencentyun-cos-java-sdk-v4
2 |
3 | java sdk for [腾讯云对象存储服务](https://www.qcloud.com/product/cos.html)
4 |
5 | sdk说明请参照[cos java sdk文档](https://www.qcloud.com/doc/product/436/6273)
6 |
7 | ## 已弃用 - 请升级到 cos-java-sdk-v5
8 | SDK 依赖的 JSON API 已弃用,请直接使用基于 XML API 的 [cos-java-sdk-v5](https://github.com/tencentyun/cos-java-sdk-v5),或者参照 [指引](https://cloud.tencent.com/document/product/436/31355) 升级到新版SDK。
9 |
10 |
11 | ## maven坐标
12 |
13 | ```xml
14 | com.qcloud
15 | cos_api
16 | 4.7
17 | ```
18 |
19 | ### 直接下载源码集成
20 | 从github下载源码装入到您的程序中
21 | 请参考示例Demo.java
22 |
23 | ## 使用范例
24 | 修改Demo.java内的appId, secretId, secretKey等信息为您的配置(可在控制台上查阅相关信息), 然后运行Demo.java。
25 |
26 |
27 | ### 常见问题:
28 |
29 | 1 引入SDK运行后,出现 java.lang.NoSuchMethodError的异常。
30 |
31 | 原因: 一般是发生了JAR包冲突,比如用户的工程中的http的JAR包版本没有A方法,但是SDK依赖的JAR包有A方法。此时运行时加载顺序的问题,加载了用户工程中的http库,运行时便会抛出NoSuchMethodError的异常。
32 |
33 | 解决方法: 将已包含的工程中引起NoSuchMethodError的包的版本和SDK中pom.xml里的对应库的版本改成一致。
34 |
--------------------------------------------------------------------------------
/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 | 4.0.0
5 | com.qcloud
6 | cos_api
7 | 4.7
8 | jar
9 | cos-java-sdk
10 | qcloud cos sdk for tencentyun
11 | https://github.com/tencentyun/cos-java-sdk
12 |
13 |
14 |
15 | cos-java-sdk
16 | https://github.com/tencentyun/cos-java-sdk
17 |
18 |
19 |
20 |
21 |
22 | chengwu
23 | chengwu@tencent.com
24 |
25 |
26 |
27 |
28 | scm:git:https://github.com/tencentyun/cos-java-sdk.git
29 | scm:git:https://github.com/tencentyun/cos-java-sdk.git
30 | https://github.com/tencentyun/cos-java-sdk
31 |
32 |
33 |
34 | UTF-8
35 | 1.6
36 | 1.6
37 |
38 |
39 |
40 |
41 | org.apache.httpcomponents
42 | httpclient
43 | 4.5.3
44 |
45 |
46 | org.apache.httpcomponents
47 | httpcore
48 | 4.4.6
49 |
50 |
51 | org.apache.httpcomponents
52 | httpmime
53 | 4.5.2
54 |
55 |
56 | org.json
57 | json
58 | 20240303
59 |
60 |
61 | org.slf4j
62 | slf4j-log4j12
63 | 1.7.21
64 |
65 |
66 | commons-codec
67 | commons-codec
68 | 1.10
69 |
70 |
71 | junit
72 | junit
73 | 4.12
74 |
75 |
76 |
77 |
78 |
79 | oss
80 | cos-java-sdk
81 |
82 | https://oss.sonatype.org/service/local/staging/deploy/maven2
83 |
84 |
85 |
86 |
87 | oss
88 | cos-java-sdk
89 |
90 | https://oss.sonatype.org/content/repositories/snapshots
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | maven-assembly-plugin
99 |
100 |
101 |
102 | com.qcloud.cos.demo.Demo
103 |
104 |
105 |
106 | jar-with-dependencies
107 |
108 |
109 |
110 |
111 |
112 | maven-source-plugin
113 | 2.1
114 |
115 | true
116 |
117 |
118 |
119 |
120 | package
121 |
122 | jar-no-fork
123 |
124 |
125 |
126 |
127 |
128 |
129 | org.apache.maven.plugins
130 | maven-javadoc-plugin
131 | 2.9.1
132 |
133 | true
134 |
135 |
136 |
137 | package
138 |
139 | jar
140 |
141 |
142 |
143 |
144 |
145 |
146 | org.apache.maven.plugins
147 | maven-gpg-plugin
148 | 1.5
149 |
150 |
151 | sign-artifacts
152 | verify
153 |
154 | sign
155 |
156 |
157 |
158 |
159 |
160 |
161 | org.codehaus.mojo
162 | cobertura-maven-plugin
163 | 2.6
164 |
165 |
166 | html
167 | xml
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 | doclint-java8-disable
177 |
178 | [1.8,)
179 |
180 |
181 |
182 |
183 |
184 | org.apache.maven.plugins
185 | maven-javadoc-plugin
186 |
187 | -Xdoclint:none
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/COS.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos;
2 |
3 | import java.io.InputStream;
4 |
5 | import com.qcloud.cos.request.CreateFolderRequest;
6 | import com.qcloud.cos.request.DelFileRequest;
7 | import com.qcloud.cos.request.DelFolderRequest;
8 | import com.qcloud.cos.request.GetFileInputStreamRequest;
9 | import com.qcloud.cos.request.GetFileLocalRequest;
10 | import com.qcloud.cos.request.ListFolderRequest;
11 | import com.qcloud.cos.request.MoveFileRequest;
12 | import com.qcloud.cos.request.StatFileRequest;
13 | import com.qcloud.cos.request.StatFolderRequest;
14 | import com.qcloud.cos.request.UpdateFileRequest;
15 | import com.qcloud.cos.request.UpdateFolderRequest;
16 | import com.qcloud.cos.request.UploadFileRequest;
17 | import com.qcloud.cos.request.UploadSliceFileRequest;
18 |
19 | /**
20 | * @author chengwu COS提供给用户使用的API接口
21 | */
22 |
23 | public interface COS {
24 |
25 | /**
26 | * 上传文件请求, 对小文件(8MB以下)使用单文件上传接口, 大文件使用分片上传接口, 推荐使用
27 | *
28 | * @param request 上传文件请求
29 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
30 | * message为success或者失败原因
31 | */
32 | String uploadFile(UploadFileRequest request);
33 |
34 | /**
35 | * 上传单文件请求, 不分片,优先推荐使用uploadFile接口
36 | *
37 | * @param request 上传文件请求
38 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
39 | * message为success或者失败原因
40 | */
41 | String uploadSingleFile(UploadFileRequest request);
42 |
43 | /**
44 | * 分片上传文件
45 | *
46 | * @param request 分片上传请求
47 | * @return JSON格式的字符串, 格式为{"code":$code, "message":$mess}, code为0表示成功, 其他为失败,
48 | * message为success或者失败原因
49 | */
50 | String uploadSliceFile(UploadSliceFileRequest request);
51 |
52 | /**
53 | * 获取文件属性
54 | *
55 | * @param request 获取文件属性请求
56 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
57 | * message为success或者失败原因
58 | */
59 | String statFile(StatFileRequest request);
60 |
61 | /**
62 | * 更新文件属性
63 | *
64 | * @param request 更新文件属性请求
65 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
66 | * message为success或者失败原因
67 | */
68 | String updateFile(UpdateFileRequest request);
69 |
70 | /**
71 | * 移动文件
72 | *
73 | * @param request 移动文件请求
74 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
75 | * message为success或者失败原因
76 | */
77 | String moveFile(MoveFileRequest request);
78 |
79 | /**
80 | * 删除文件
81 | *
82 | * @param request 删除文件请求
83 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
84 | * message为success或者失败原因
85 | */
86 | String delFile(DelFileRequest request);
87 |
88 |
89 |
90 | /**
91 | * 下载文件到本地
92 | *
93 | * @param request
94 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
95 | * message为success或者失败原因
96 | */
97 | String getFileLocal(GetFileLocalRequest request);
98 |
99 | /**
100 | * 下载文件并得到下载流
101 | *
102 | * @param request
103 | * @return 下载输入流
104 | */
105 | InputStream getFileInputStream(GetFileInputStreamRequest request) throws Exception;
106 |
107 | /**
108 | * 创建目录
109 | *
110 | * @param request 创建目录请求
111 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
112 | * message为success或者失败原因
113 | */
114 | String createFolder(CreateFolderRequest request);
115 |
116 | /**
117 | * 更新目录属性
118 | *
119 | * @param request 更新目录属性请求
120 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
121 | * message为success或者失败原因
122 | */
123 | String updateFolder(UpdateFolderRequest request);
124 |
125 | /**
126 | * 获取目录属性请求
127 | *
128 | * @param request 获取目录属性请求
129 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
130 | * message为success或者失败原因
131 | */
132 | String statFolder(StatFolderRequest request);
133 |
134 | /**
135 | * 获取目录列表请求
136 | *
137 | * @param request 获取目录列表请求
138 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
139 | * message为success或者失败原因
140 | */
141 | String listFolder(ListFolderRequest request);
142 |
143 | /**
144 | * 删除目录请求
145 | *
146 | * @param request 删除目录请求
147 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
148 | * message为success或者失败原因
149 | */
150 | String delFolder(DelFolderRequest request);
151 |
152 | /**
153 | * 关闭COS客户端连接池,释放涉及的资源,释放后,不能再使用COS的接口,必须重新生成一个新对象
154 | */
155 | void shutdown();
156 |
157 | }
158 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/COSClient.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos;
2 |
3 | import com.qcloud.cos.request.UpdateFileRequest;
4 | import com.qcloud.cos.request.UpdateFolderRequest;
5 | import com.qcloud.cos.request.UploadFileRequest;
6 | import com.qcloud.cos.request.UploadSliceFileRequest;
7 | import com.qcloud.cos.sign.Credentials;
8 |
9 | import java.io.InputStream;
10 |
11 | import org.slf4j.Logger;
12 | import org.slf4j.LoggerFactory;
13 |
14 | import com.qcloud.cos.exception.AbstractCosException;
15 | import com.qcloud.cos.exception.UnknownException;
16 | import com.qcloud.cos.http.AbstractCosHttpClient;
17 | import com.qcloud.cos.http.DefaultCosHttpClient;
18 | import com.qcloud.cos.op.FileOp;
19 | import com.qcloud.cos.op.FolderOp;
20 | import com.qcloud.cos.request.AbstractBaseRequest;
21 | import com.qcloud.cos.request.CreateFolderRequest;
22 | import com.qcloud.cos.request.DelFileRequest;
23 | import com.qcloud.cos.request.DelFolderRequest;
24 | import com.qcloud.cos.request.GetFileInputStreamRequest;
25 | import com.qcloud.cos.request.GetFileLocalRequest;
26 | import com.qcloud.cos.request.ListFolderRequest;
27 | import com.qcloud.cos.request.MoveFileRequest;
28 | import com.qcloud.cos.request.StatFileRequest;
29 | import com.qcloud.cos.request.StatFolderRequest;
30 |
31 | /**
32 | * @author chengwu 封装Cos JAVA SDK暴露给用户的接口函数
33 | */
34 | public class COSClient implements COS {
35 |
36 | private static final Logger LOG = LoggerFactory.getLogger(COSClient.class);
37 |
38 | private ClientConfig config;
39 | private Credentials cred;
40 | private AbstractCosHttpClient client;
41 |
42 | private FileOp fileOp;
43 | private FolderOp folderOp;
44 |
45 | public COSClient(long appId, String secretId, String secretKey) {
46 | this(new Credentials(appId, secretId, secretKey));
47 | }
48 |
49 | public COSClient(Credentials cred) {
50 | this(new ClientConfig(), cred);
51 | }
52 |
53 | public void setConfig(ClientConfig config) {
54 | this.config = config;
55 | this.fileOp.setConfig(config);
56 | this.folderOp.setConfig(config);
57 | this.client.shutdown();
58 | this.client = new DefaultCosHttpClient(config);
59 | this.fileOp.setHttpClient(this.client);
60 | this.folderOp.setHttpClient(this.client);
61 | }
62 |
63 | public void setCred(Credentials cred) {
64 | this.cred = cred;
65 | this.fileOp.setCred(cred);
66 | this.folderOp.setCred(cred);
67 | }
68 |
69 | public COSClient(ClientConfig config, Credentials cred) {
70 | this.config = config;
71 | this.cred = cred;
72 | this.client = new DefaultCosHttpClient(config);
73 | fileOp = new FileOp(this.config, this.cred, this.client);
74 | folderOp = new FolderOp(this.config, this.cred, this.client);
75 | }
76 |
77 | private void recordException(String methodName, AbstractBaseRequest request, String message) {
78 | LOG.warn(methodName + " occur a exception, request:{}, message:{}", request, message);
79 | }
80 |
81 | @Override
82 | public String updateFolder(UpdateFolderRequest request) {
83 | try {
84 | return folderOp.updateFolder(request);
85 | } catch (AbstractCosException e) {
86 | recordException("updateFolder", request, e.toString());
87 | return e.toString();
88 | } catch (Exception e) {
89 | UnknownException e1 = new UnknownException(e.toString());
90 | recordException("updateFolder", request, e1.toString());
91 | return e1.toString();
92 | }
93 | }
94 |
95 | @Override
96 | public String updateFile(UpdateFileRequest request) {
97 | try {
98 | return fileOp.updateFile(request);
99 | } catch (AbstractCosException e) {
100 | recordException("updateFile", request, e.toString());
101 | return e.toString();
102 | } catch (Exception e) {
103 | UnknownException e1 = new UnknownException(e.toString());
104 | recordException("updateFile", request, e1.toString());
105 | return e1.toString();
106 | }
107 | }
108 |
109 | @Override
110 | public String delFolder(DelFolderRequest request) {
111 | try {
112 | return folderOp.delFolder(request);
113 | } catch (AbstractCosException e) {
114 | recordException("deleteFolder", request, e.toString());
115 | return e.toString();
116 | } catch (Exception e) {
117 | UnknownException e1 = new UnknownException(e.toString());
118 | recordException("deleteFolder", request, e1.toString());
119 | return e1.toString();
120 | }
121 | }
122 |
123 | @Override
124 | public String moveFile(MoveFileRequest request) {
125 | try {
126 | return fileOp.moveFile(request);
127 | } catch (AbstractCosException e) {
128 | recordException("moveFile", request, e.toString());
129 | return e.toString();
130 | } catch (Exception e) {
131 | UnknownException e1 = new UnknownException(e.toString());
132 | recordException("moveFile", request, e1.toString());
133 | return e1.toString();
134 | }
135 | }
136 |
137 | @Override
138 | public String delFile(DelFileRequest request) {
139 | try {
140 | return fileOp.delFile(request);
141 | } catch (AbstractCosException e) {
142 | recordException("deleteFile", request, e.toString());
143 | return e.toString();
144 | } catch (Exception e) {
145 | UnknownException e1 = new UnknownException(e.toString());
146 | recordException("deleteFile", request, e1.toString());
147 | return e1.toString();
148 | }
149 | }
150 |
151 | @Override
152 | public String statFolder(StatFolderRequest request) {
153 | try {
154 | return folderOp.statFolder(request);
155 | } catch (AbstractCosException e) {
156 | recordException("getFolderStat", request, e.toString());
157 | return e.toString();
158 | } catch (Exception e) {
159 | UnknownException e1 = new UnknownException(e.toString());
160 | recordException("getFolderStat", request, e1.toString());
161 | return e1.toString();
162 | }
163 | }
164 |
165 | @Override
166 | public String statFile(StatFileRequest request) {
167 | try {
168 | return fileOp.statFile(request);
169 | } catch (AbstractCosException e) {
170 | recordException("getFileStat", request, e.toString());
171 | return e.toString();
172 | } catch (Exception e) {
173 | UnknownException e1 = new UnknownException(e.toString());
174 | recordException("getFileStat", request, e1.toString());
175 | return e1.toString();
176 | }
177 | }
178 |
179 | @Override
180 | public String createFolder(CreateFolderRequest request) {
181 | try {
182 | return folderOp.createFolder(request);
183 | } catch (AbstractCosException e) {
184 | recordException("createFolder", request, e.toString());
185 | return e.toString();
186 | } catch (Exception e) {
187 | UnknownException e1 = new UnknownException(e.toString());
188 | recordException("createFolder", request, e1.toString());
189 | return e1.toString();
190 | }
191 | }
192 |
193 | @Override
194 | public String listFolder(ListFolderRequest request) {
195 | try {
196 | return folderOp.listFolder(request);
197 | } catch (AbstractCosException e) {
198 | recordException("getFolderList", request, e.toString());
199 | return e.toString();
200 | } catch (Exception e) {
201 | UnknownException e1 = new UnknownException(e.toString());
202 | recordException("getFolderList", request, e1.toString());
203 | return e1.toString();
204 | }
205 | }
206 |
207 | @Override
208 | public String uploadFile(UploadFileRequest request) {
209 | try {
210 | return fileOp.uploadFile(request);
211 | } catch (AbstractCosException e) {
212 | recordException("uploadFile", request, e.toString());
213 | return e.toString();
214 | } catch (Exception e) {
215 | UnknownException e1 = new UnknownException(e.toString());
216 | recordException("uploadFile", request, e1.toString());
217 | return e1.toString();
218 | }
219 | }
220 |
221 | @Override
222 | public String uploadSingleFile(UploadFileRequest request) {
223 | try {
224 | return fileOp.uploadSingleFile(request);
225 | } catch (AbstractCosException e) {
226 | recordException("uploadSingleFile", request, e.toString());
227 | return e.toString();
228 | } catch (Exception e) {
229 | UnknownException e1 = new UnknownException(e.toString());
230 | recordException("uploadSingleFile", request, e1.toString());
231 | return e1.toString();
232 | }
233 | }
234 |
235 | @Override
236 | public String uploadSliceFile(UploadSliceFileRequest request) {
237 | try {
238 | return fileOp.uploadSliceFile(request);
239 | } catch (AbstractCosException e) {
240 | recordException("uploadSliceFile", request, e.toString());
241 | return e.toString();
242 | } catch (Exception e) {
243 | UnknownException e1 = new UnknownException(e.toString());
244 | recordException("uploadSliceFile", request, e1.toString());
245 | return e1.toString();
246 | }
247 | }
248 |
249 | @Override
250 | public InputStream getFileInputStream(GetFileInputStreamRequest request) throws Exception {
251 | try {
252 | return fileOp.getFileInputStream(request);
253 | } catch (AbstractCosException e) {
254 | recordException("getFileInputStream", request, e.toString());
255 | throw new Exception(e.getMessage());
256 | } catch (Exception e) {
257 | UnknownException e1 = new UnknownException(e.toString());
258 | recordException("getFileInputStream", request, e1.toString());
259 | throw new Exception(e.getMessage());
260 | }
261 | }
262 |
263 | @Override
264 | public String getFileLocal(GetFileLocalRequest request) {
265 | try {
266 | return fileOp.getFileLocal(request);
267 | } catch (AbstractCosException e) {
268 | recordException("getFileLocalRequest", request, e.toString());
269 | return e.toString();
270 | } catch (Exception e) {
271 | UnknownException e1 = new UnknownException(e.toString());
272 | recordException("getFileLocalRequest", request, e1.toString());
273 | return e1.toString();
274 | }
275 | }
276 | @Override
277 | public void shutdown() {
278 | this.client.shutdown();
279 | }
280 |
281 | }
282 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/ClientConfig.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos;
2 |
3 | public class ClientConfig {
4 | // cos server的上传域名前缀, 用来表明使用的协议
5 | private static final String UPLOAD_COS_ENDPOINT_PREFIX = "http://";
6 | // cos server的上传域名地址
7 | private static final String UPLOAD_COS_ENDPOINT_DOMAIN = "gz.file.myqcloud.com";
8 | // cos server的上传域名的后缀
9 | private static final String UPLOAD_COS_ENDPOINT_SUFFIX = "/files/v2";
10 | // cos server的下载域名的前缀
11 | private static final String DOWN_COS_ENDPOINT_PREFIX = "http://";
12 | // cos server的下载域名地址
13 | private static final String DOWN_COS_ENDPOINT_DOMAIN = "cosgz.myqcloud.com";
14 | // 多次签名的默认过期时间,单位秒
15 | private static final int DEFAULT_SIGN_EXPIRED = 300;
16 | // 默认的最大重试次数(发生了socketException时)
17 | private static final int DEFAULT_MAX_RETRIES = 3;
18 | // 默认的获取连接的超时时间
19 | private static final int DEFAULT_CONNECTION_REQUEST_TIMEOUT = -1;
20 | // 默认连接超时, 单位ms
21 | private static final int DEFAULT_CONNECTION_TIMEOUT = 30 * 1000;
22 | // 默认的SOCKET读取超时时间, 默认毫秒
23 | private static final int DEFAULT_SOCKET_TIMEOUT = 30 * 1000;
24 | // 默认的维护最大HTTP连接数
25 | private static final int DEFAULT_MAX_CONNECTIONS_COUNT = 1024;
26 | // 默认的user_agent标识
27 | private static final String DEFAULT_USER_AGENT = "cos-java-sdk-v4.7";
28 |
29 | private String uploadCosEndPointPrefix = UPLOAD_COS_ENDPOINT_PREFIX;
30 | private String uploadCosEndPointDomain = UPLOAD_COS_ENDPOINT_DOMAIN;
31 | private String uploadCosEndPointSuffix = UPLOAD_COS_ENDPOINT_SUFFIX;
32 | private String downCosEndPointPrefix = DOWN_COS_ENDPOINT_PREFIX;
33 | private String downCosEndPointDomain = DOWN_COS_ENDPOINT_DOMAIN;
34 | private int signExpired = DEFAULT_SIGN_EXPIRED;
35 | private int maxFailedRetry = DEFAULT_MAX_RETRIES;
36 | private int connectionRequestTimeout = DEFAULT_CONNECTION_REQUEST_TIMEOUT;
37 | private int connectionTimeout = DEFAULT_CONNECTION_TIMEOUT;
38 | private int socketTimeout = DEFAULT_SOCKET_TIMEOUT;
39 | private int maxConnectionsCount = DEFAULT_MAX_CONNECTIONS_COUNT;
40 | private String userAgent = DEFAULT_USER_AGENT;
41 |
42 | // http proxy代理,如果使用http proxy代理,需要设置IP与端口
43 | private String httpProxyIp = null;
44 | private int httpProxyPort = 0;
45 |
46 |
47 | public int getMaxFailedRetry() {
48 | return maxFailedRetry;
49 | }
50 |
51 | public void setMaxFailedRetry(int maxFailedRetry) {
52 | this.maxFailedRetry = maxFailedRetry;
53 | }
54 |
55 | public int getSignExpired() {
56 | return signExpired;
57 | }
58 |
59 | public void setSignExpired(int signExpired) {
60 | this.signExpired = signExpired;
61 | }
62 |
63 | public int getConnectionRequestTimeout() {
64 | return connectionRequestTimeout;
65 | }
66 |
67 | public void setConnectionRequestTimeout(int connectionRequestTimeout) {
68 | this.connectionRequestTimeout = connectionRequestTimeout;
69 | }
70 |
71 | public int getConnectionTimeout() {
72 | return connectionTimeout;
73 | }
74 |
75 | public void setConnectionTimeout(int connectionTimeout) {
76 | this.connectionTimeout = connectionTimeout;
77 | }
78 |
79 | public int getSocketTimeout() {
80 | return socketTimeout;
81 | }
82 |
83 | public void setSocketTimeout(int socketTimeout) {
84 | this.socketTimeout = socketTimeout;
85 | }
86 |
87 | public int getMaxConnectionsCount() {
88 | return maxConnectionsCount;
89 | }
90 |
91 | public void setMaxConnectionsCount(int maxConnectionsCount) {
92 | this.maxConnectionsCount = maxConnectionsCount;
93 | }
94 |
95 | public String getUserAgent() {
96 | return userAgent;
97 | }
98 |
99 | public void setUserAgent(String userAgent) {
100 | this.userAgent = userAgent;
101 | }
102 |
103 | public String getUploadCosEndPointDomain() {
104 | return uploadCosEndPointDomain;
105 | }
106 |
107 | public void setUploadCosEndPointDomain(String cosEndpoint) {
108 | this.uploadCosEndPointDomain = cosEndpoint;
109 | }
110 |
111 | public String getDownCosEndPointDomain() {
112 | return downCosEndPointDomain;
113 | }
114 |
115 | public void setDownCosEndPointDomain(String downCosEndPoint) {
116 | this.downCosEndPointDomain = downCosEndPoint;
117 | }
118 |
119 | public String getUploadCosEndPointPrefix() {
120 | return uploadCosEndPointPrefix;
121 | }
122 |
123 | public void setUploadCosEndPointPrefix(String uploadCosEndPointPrefix) {
124 | this.uploadCosEndPointPrefix = uploadCosEndPointPrefix;
125 | }
126 |
127 | public String getUploadCosEndPointSuffix() {
128 | return uploadCosEndPointSuffix;
129 | }
130 |
131 | public void setUploadCosEndPointSuffix(String uploadCosEndPointSuffix) {
132 | this.uploadCosEndPointSuffix = uploadCosEndPointSuffix;
133 | }
134 |
135 | public String getDownCosEndPointPrefix() {
136 | return downCosEndPointPrefix;
137 | }
138 |
139 | public void setDownCosEndPointPrefix(String downCosEndPointPrefix) {
140 | this.downCosEndPointPrefix = downCosEndPointPrefix;
141 | }
142 |
143 | public void setRegion(String region) {
144 | this.uploadCosEndPointDomain = region + ".file.myqcloud.com";
145 | this.downCosEndPointDomain = "cos" + region + ".myqcloud.com";
146 | }
147 |
148 | public String getHttpProxyIp() {
149 | return httpProxyIp;
150 | }
151 |
152 | public void setHttpProxyIp(String httpProxyIp) {
153 | this.httpProxyIp = httpProxyIp;
154 | }
155 |
156 | public int getHttpProxyPort() {
157 | return httpProxyPort;
158 | }
159 |
160 | public void setHttpProxyPort(int httpProxyPort) {
161 | this.httpProxyPort = httpProxyPort;
162 | }
163 | }
164 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/ErrorCode.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos;
2 |
3 | /**
4 | * @author chengwu
5 | * cos返回给用户的错误码信息, code为0为成功
6 | * 此处的错误码是SDK包括:用户的参数错误(如路径不符合), 网络错误(无法和cos服务端通信), 服务端故障, 其他未知错误
7 | */
8 | public class ErrorCode {
9 | public static final int PARAMS_ERROR = -1; // 参数错误
10 | public static final int NETWORK_ERROR = -2; // 网络错误
11 | public static final int SERVER_ERROR = -3; // 服务端故障
12 | public static final int UNKNOWN_ERROR = -4; // 其他未知错误
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/common_utils/CommonCodecUtils.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.common_utils;
2 |
3 | import org.apache.commons.codec.Charsets;
4 | import org.apache.commons.codec.binary.Base64;
5 | import org.apache.commons.codec.digest.DigestUtils;
6 | import org.json.JSONArray;
7 | import org.json.JSONObject;
8 | import org.slf4j.Logger;
9 | import org.slf4j.LoggerFactory;
10 |
11 | import com.qcloud.cos.http.RequestBodyKey;
12 |
13 | import java.io.ByteArrayInputStream;
14 | import java.io.IOException;
15 | import java.io.InputStream;
16 | import java.security.InvalidKeyException;
17 | import java.security.NoSuchAlgorithmException;
18 |
19 | import javax.crypto.Mac;
20 | import javax.crypto.spec.SecretKeySpec;
21 |
22 | /**
23 | * @author chengwu 封装了常用的MD5、SHA1、HmacSha1函数
24 | */
25 | public class CommonCodecUtils {
26 |
27 | private static final Logger LOG = LoggerFactory.getLogger(CommonCodecUtils.class);
28 |
29 | private static final String HMAC_SHA1 = "HmacSHA1";
30 |
31 | /**
32 | * 对二进制数据进行BASE64编码
33 | *
34 | * @param binaryData 二进制数据
35 | * @return 编码后的字符串
36 | */
37 | public static String Base64Encode(byte[] binaryData) {
38 | String encodedstr = new String(Base64.encodeBase64(binaryData, false), Charsets.UTF_8);
39 | return encodedstr;
40 | }
41 |
42 | /**
43 | * 获取buffer内容的sha1
44 | *
45 | * @param contentBuffer 要计算sha1的buffer
46 | * @return 编码后的字符串
47 | * @throws Exception
48 | */
49 | public static String getBufferSha1(byte[] contentBuffer) throws Exception {
50 | return DigestUtils.sha1Hex(contentBuffer);
51 | }
52 |
53 | /**
54 | * 获取整个文件的SHA1
55 | *
56 | * @param fileInputStream 文件的输入流
57 | * @return 文件对应的SHA1值
58 | * @throws Exception
59 | */
60 | public static String getEntireFileSha1(String filePath) throws Exception {
61 | InputStream fileInputStream = null;
62 | try {
63 | fileInputStream = CommonFileUtils.getFileInputStream(filePath);
64 | String sha1Digest = DigestUtils.sha1Hex(fileInputStream);
65 | return sha1Digest;
66 | } catch (Exception e) {
67 | String errMsg = "getFileSha1 occur a exception, file:" + filePath + ", exception:"
68 | + e.toString();
69 | LOG.error(errMsg);
70 | throw new Exception(errMsg);
71 | } finally {
72 | try {
73 | CommonFileUtils.closeFileStream(fileInputStream, filePath);
74 | } catch (Exception e) {
75 | throw e;
76 | }
77 | }
78 | }
79 |
80 | /**
81 | * 获取分片的sha1, 并以JSON数组字符串的形式返回,每一个成员都是分片的sha信息
82 | * 除最后一片外,每一片的sha信息都是中间状态,即sha算法update后的五个常量值的十六进制字符串 因此最后一片的sha值和全文sha是一样的
83 | *
84 | * @param localPath 本地文件路径
85 | * @param sliceSize 分片大小
86 | * @param entireSha1Builder 存储全文sha的对象
87 | * @return 返回分片sha的JSON格式的字符串
88 | * @throws Exception
89 | */
90 | public static String getSlicePartSha1(String localPath, int sliceSize,
91 | StringBuilder entireSha1Builder) throws Exception {
92 | // 超过1M的按照1M来计算sha
93 | if (sliceSize > 1024 * 1024) {
94 | sliceSize = 1024 * 1024;
95 | }
96 |
97 | JSONArray jsonArray = new JSONArray();
98 | InputStream fileInput = null;
99 | try {
100 | CommonSha1Utils sha1Utils = new CommonSha1Utils();
101 | sha1Utils.init();
102 |
103 | fileInput = CommonFileUtils.getFileInputStream(localPath);
104 | long fileLength = CommonFileUtils.getFileLength(localPath);
105 | int sliceCount = new Long((fileLength + (sliceSize - 1)) / sliceSize).intValue();
106 |
107 | final int BUFFER_LEN = 1024;
108 | byte[] contentBuf = null;
109 |
110 | // 先求第一片到倒数第二片的sha信息,这些片的大小都是sliceSize
111 | for (int sliceIndex = 0; sliceIndex < sliceCount - 1; ++sliceIndex) {
112 | int totalCount = 0;
113 | long sliceOffset = sliceIndex;
114 | sliceOffset *= sliceSize;
115 |
116 | while (totalCount < sliceSize) {
117 | int maxRead = sliceSize - totalCount;
118 | if (maxRead > BUFFER_LEN) {
119 | maxRead = BUFFER_LEN;
120 | }
121 | contentBuf = new byte[maxRead];
122 | fileInput.read(contentBuf, 0, maxRead);
123 | sha1Utils.update(contentBuf);
124 | totalCount += maxRead;
125 | }
126 |
127 | JSONObject sliceJson = new JSONObject();
128 | sliceJson.put(RequestBodyKey.UploadParts.OFFSET, sliceOffset);
129 | sliceJson.put(RequestBodyKey.UploadParts.DATA_LEN, totalCount);
130 | sliceJson.put(RequestBodyKey.UploadParts.DATA_SHA, sha1Utils.dumpTempState());
131 | jsonArray.put(sliceIndex, sliceJson);
132 | }
133 |
134 | // 求最后一片的sha信息
135 | long sliceOffset = (sliceCount - 1) * (long)sliceSize;
136 | int leftSlice = new Long(fileLength - sliceOffset).intValue();
137 | int totalCount = 0;
138 | while (totalCount < leftSlice) {
139 | int maxRead = leftSlice - totalCount;
140 | if (maxRead > BUFFER_LEN) {
141 | maxRead = BUFFER_LEN;
142 | }
143 | contentBuf = new byte[maxRead];
144 | fileInput.read(contentBuf, 0, maxRead);
145 | sha1Utils.update(contentBuf);
146 | totalCount += maxRead;
147 | }
148 | sha1Utils.finish();
149 |
150 | entireSha1Builder.append(sha1Utils.digout());
151 |
152 | JSONObject sliceJson = new JSONObject();
153 | sliceJson.put(RequestBodyKey.UploadParts.OFFSET, sliceOffset);
154 | sliceJson.put(RequestBodyKey.UploadParts.DATA_LEN, totalCount);
155 | sliceJson.put(RequestBodyKey.UploadParts.DATA_SHA, sha1Utils.digout());
156 | jsonArray.put(sliceCount - 1, sliceJson);
157 |
158 | } catch (Exception e) {
159 | LOG.error("getSlicePartSha1 occur a error, filePath:{}, sliceSize:{}, exception:{}",
160 | localPath, sliceSize, e.toString());
161 | throw e;
162 | } finally {
163 | CommonFileUtils.closeFileStream(fileInput, localPath);
164 | }
165 | return jsonArray.toString();
166 | }
167 |
168 | public static String getSlicePartSha1(byte[] contentBuffer, int sliceSize,
169 | StringBuilder entireSha1Builder) throws Exception {
170 | // 超过1M的按照1M来计算sha
171 | if (sliceSize > 1024 * 1024) {
172 | sliceSize = 1024 * 1024;
173 | }
174 |
175 | JSONArray jsonArray = new JSONArray();
176 | InputStream fileInput = null;
177 | try {
178 | CommonSha1Utils sha1Utils = new CommonSha1Utils();
179 | sha1Utils.init();
180 |
181 | fileInput = new ByteArrayInputStream(contentBuffer);
182 | long fileLength = contentBuffer.length;
183 | int sliceCount = new Long((fileLength + (sliceSize - 1)) / sliceSize).intValue();
184 |
185 | final int BUFFER_LEN = 1024;
186 | byte[] contentBuf = null;
187 |
188 | // 先求第一片到倒数第二片的sha信息,这些片的大小都是sliceSize
189 | for (int sliceIndex = 0; sliceIndex < sliceCount - 1; ++sliceIndex) {
190 | int totalCount = 0;
191 | long sliceOffset = sliceIndex * (long)sliceSize;
192 |
193 | while (totalCount < sliceSize) {
194 | int maxRead = sliceSize - totalCount;
195 | if (maxRead > BUFFER_LEN) {
196 | maxRead = BUFFER_LEN;
197 | }
198 | contentBuf = new byte[maxRead];
199 | fileInput.read(contentBuf, 0, maxRead);
200 | sha1Utils.update(contentBuf);
201 | totalCount += maxRead;
202 | }
203 |
204 | JSONObject sliceJson = new JSONObject();
205 | sliceJson.put(RequestBodyKey.UploadParts.OFFSET, sliceOffset);
206 | sliceJson.put(RequestBodyKey.UploadParts.DATA_LEN, totalCount);
207 | sliceJson.put(RequestBodyKey.UploadParts.DATA_SHA, sha1Utils.dumpTempState());
208 | jsonArray.put(sliceIndex, sliceJson);
209 | }
210 |
211 | // 求最后一片的sha信息
212 | long sliceOffset = (sliceCount - 1) * (long)sliceSize;
213 | int leftSlice = new Long(fileLength - sliceOffset).intValue();
214 | int totalCount = 0;
215 | while (totalCount < leftSlice) {
216 | int maxRead = leftSlice - totalCount;
217 | if (maxRead > BUFFER_LEN) {
218 | maxRead = BUFFER_LEN;
219 | }
220 | contentBuf = new byte[maxRead];
221 | fileInput.read(contentBuf, 0, maxRead);
222 | sha1Utils.update(contentBuf);
223 | totalCount += maxRead;
224 | }
225 | sha1Utils.finish();
226 |
227 | entireSha1Builder.append(sha1Utils.digout());
228 |
229 | JSONObject sliceJson = new JSONObject();
230 | sliceJson.put(RequestBodyKey.UploadParts.OFFSET, sliceOffset);
231 | sliceJson.put(RequestBodyKey.UploadParts.DATA_LEN, totalCount);
232 | sliceJson.put(RequestBodyKey.UploadParts.DATA_SHA, sha1Utils.digout());
233 | jsonArray.put(sliceCount - 1, sliceJson);
234 |
235 | } catch (Exception e) {
236 | LOG.error("getSlicePartSha1 from buffer occur a error, sliceSize:{}, exception:{}",
237 | sliceSize, e.toString());
238 | throw e;
239 | } finally {
240 | if (fileInput != null) {
241 | try {
242 | fileInput.close();
243 | } catch (IOException e) {
244 | }
245 | }
246 | }
247 |
248 | return jsonArray.toString();
249 | }
250 |
251 | /**
252 | * 计算数据的Hmac值
253 | *
254 | * @param binaryData 二进制数据
255 | * @param key 秘钥
256 | * @return 加密后的hmacsha1值
257 | */
258 | public static byte[] HmacSha1(byte[] binaryData, String key) throws Exception {
259 | try {
260 | Mac mac = Mac.getInstance(HMAC_SHA1);
261 | SecretKeySpec secretKey = new SecretKeySpec(key.getBytes(), HMAC_SHA1);
262 | mac.init(secretKey);
263 | byte[] HmacSha1Digest = mac.doFinal(binaryData);
264 | return HmacSha1Digest;
265 |
266 | } catch (NoSuchAlgorithmException e) {
267 | LOG.error("mac not find algorithm {}", HMAC_SHA1);
268 | throw e;
269 | } catch (InvalidKeyException e) {
270 | LOG.error("mac init key {} occur a error {}", key, e.toString());
271 | throw e;
272 | } catch (IllegalStateException e) {
273 | LOG.error("mac.doFinal occur a error {}", e.toString());
274 | throw e;
275 | }
276 | }
277 |
278 | /**
279 | * 计算数据的Hmac值
280 | *
281 | * @param plainText 文本数据
282 | * @param key 秘钥
283 | * @return 加密后的hmacsha1值
284 | */
285 | public static byte[] HmacSha1(String plainText, String key) throws Exception {
286 | return HmacSha1(plainText.getBytes(), key);
287 | }
288 | }
289 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/common_utils/CommonFileUtils.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.common_utils;
2 |
3 | import java.io.File;
4 | import java.io.FileInputStream;
5 | import java.io.FileNotFoundException;
6 | import java.io.IOException;
7 | import java.io.InputStream;
8 | import java.nio.charset.Charset;
9 |
10 | import org.slf4j.Logger;
11 | import org.slf4j.LoggerFactory;
12 |
13 | /**
14 | * @author chengwu
15 | * 封装了一些常用的文件操作函数
16 | */
17 | public class CommonFileUtils {
18 |
19 | private static Logger LOG = LoggerFactory.getLogger(CommonFileUtils.class);
20 |
21 | /**
22 | * 判断指定路径的文件是否有效, 即文件存在,且可读
23 | * @param filePath
24 | * @return 有效返回true, 否则返回false
25 | */
26 | public static boolean isLegalFile(String filePath) {
27 | File file = new File(filePath);
28 | if (!file.exists() || file.isDirectory() || !file.canRead()) {
29 | return false;
30 | }
31 | return true;
32 | }
33 |
34 | /**
35 | * 获取文件长度,单位为字节
36 | *
37 | * @param filePath 文件的本地路径
38 | * @return 文件长度,单位为字节
39 | * @throws Exception 文件不存在或者是一个目录,则抛出异常
40 | */
41 | public static long getFileLength(String filePath) throws Exception {
42 | File file = new File(filePath);
43 | return file.length();
44 | }
45 |
46 | /**
47 | * 打开对应的文件,并返回文件输入流
48 | *
49 | * @param filePath 文件路径
50 | * @return 文件输入流
51 | * @throws FileNotFoundException 如果文件不存在,则抛出异常
52 | */
53 | public static FileInputStream getFileInputStream(String filePath) throws Exception {
54 | FileInputStream localFileInputStream = new FileInputStream(filePath);
55 | return localFileInputStream;
56 | }
57 |
58 | /**
59 | * 关闭对应的文件流
60 | *
61 | * @param inputStream 待关闭的文件流
62 | * @param filePath 对应的文件名
63 | * @throws IOException 关闭时发生IO异常,则抛出
64 | */
65 | public static void closeFileStream(InputStream inputStream, String filePath){
66 | try {
67 | if (inputStream != null) {
68 | inputStream.close();
69 | }
70 | } catch (IOException e) {
71 | LOG.error("close file {} occur an IOExcpetion {}", filePath, e);
72 | }
73 | }
74 |
75 | /**
76 | * 获取小文件的全部内容
77 | *
78 | * @param filePath
79 | * @return
80 | * @throws Exception
81 | */
82 | public static String getFileContent(String filePath) throws Exception {
83 | int fileLength = ((Long) getFileLength(filePath)).intValue();
84 | return getFileContent(filePath, 0, fileLength);
85 | }
86 |
87 | /**
88 | * 获取文件指定块的内容
89 | *
90 | * @param filePath 文件路径
91 | * @param offset 偏移量,即从哪里开始读取,单位为字节
92 | * @param length 读取的长度,单位为字节
93 | * @return 返回读取的内容,实际读取的长度小于等于length
94 | * @throws Exception
95 | */
96 | public static String getFileContent(String filePath, long offset, int length) throws Exception {
97 | FileInputStream fileInputStream = null;
98 | try {
99 | fileInputStream = getFileInputStream(filePath);
100 | return getFileContent(fileInputStream, offset, length);
101 | } finally {
102 | closeFileStream(fileInputStream, filePath);
103 | }
104 | }
105 |
106 | /**
107 | * 读取指定流从某处开始的内容,此函数有一定的风险,如果流对应的内容过大,则会造成OOM
108 | *
109 | * @param inputStream
110 | * @param offset 读取的开始偏移
111 | * @param length 读取的长度
112 | * @return 读取的内容
113 | * @throws Exception
114 | */
115 | public static String getFileContent(InputStream inputStream, long offset, int length)
116 | throws Exception {
117 | byte[] fileContent = getFileContentByte(inputStream, offset, length);
118 | return new String(fileContent, Charset.forName("ISO-8859-1"));
119 | }
120 |
121 | public static byte[] getFileContentByte(InputStream inputStream, long offset, int length)
122 | throws Exception {
123 | if (offset < 0 || length < 0) {
124 | throw new Exception("getFileContent param error");
125 | }
126 |
127 | byte[] fileContent = null;
128 | byte[] tempBuf = new byte[length];
129 |
130 | inputStream.skip(offset);
131 | int readLen = inputStream.read(tempBuf);
132 | if (readLen < 0) {
133 | fileContent = new byte[0];
134 | return fileContent;
135 | }
136 | if (readLen < length) {
137 | fileContent = new byte[readLen];
138 | System.arraycopy(tempBuf, 0, fileContent, 0, readLen);
139 | } else {
140 | fileContent = tempBuf;
141 | }
142 | return fileContent;
143 | }
144 |
145 | /**
146 | * 删除文件
147 | * @param filePath 文件路径
148 | */
149 | public static void remove(String filePath) {
150 | File file = new File(filePath);
151 | if (file.exists() && file.isFile()) {
152 | file.delete();
153 | }
154 | }
155 |
156 | /**
157 | * 获取文件上次的修改时间
158 | *
159 | * @param filePath 文件的本地路径
160 | * @return 文件长度,单位为字节
161 | * @throws Exception 文件不存在或者是一个目录,则抛出异常
162 | */
163 | public static long getFileLastModified(String filePath) throws Exception {
164 | if (!isLegalFile(filePath)) {
165 | String errorMsg = filePath + " is not file or not exist or can't be read!";
166 | LOG.error(errorMsg);
167 | throw new Exception(errorMsg);
168 | }
169 | File file = new File(filePath);
170 | return file.lastModified();
171 | }
172 | }
173 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/common_utils/CommonParamCheckUtils.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.common_utils;
2 |
3 | import java.util.Map;
4 | import java.util.regex.Matcher;
5 | import java.util.regex.Pattern;
6 |
7 | import com.qcloud.cos.exception.ParamException;
8 |
9 | /**
10 | * @author chengwu 封装一些参数检查的类,如果检查未通过抛出参数异常
11 | */
12 | public class CommonParamCheckUtils {
13 |
14 | /**
15 | * 判断参数是否为NULL,如果为NULL,抛出参数异常
16 | *
17 | * @param objName
18 | * 参数名
19 | * @param obj
20 | * 参数对象
21 | * @throws ParamException
22 | */
23 | public static void AssertNotNull(String objName, Object obj) throws ParamException {
24 | if (obj == null) {
25 | throw new ParamException(objName + " is null, please check!");
26 | }
27 | }
28 |
29 | /**
30 | * 判断文件是否适合使用整文件上传,使用范围0 ~ 10MB, 大文件应该用分片上传
31 | *
32 | * @param localFilePath
33 | * 本地文件路径
34 | * @throws ParamException
35 | */
36 | public static void AssertUploadEntireFileInRange(String localFilePath) throws ParamException {
37 | long fileSize = 0;
38 | try {
39 | fileSize = CommonFileUtils.getFileLength(localFilePath);
40 | } catch (Exception e) {
41 | throw new ParamException(localFilePath + " is not effective file!");
42 | }
43 |
44 | long maxFileSize = 10 * 1024 * 1024;
45 | if (fileSize > maxFileSize) {
46 | throw new ParamException(localFilePath + " is too large, please use uploadSliceFile interface!");
47 | }
48 | }
49 |
50 | /**
51 | * 判断分片尺寸是否在规定的范围内,抛出参数异常,目前的有效值为64KB ~ 10MB
52 | *
53 | * @param sliceSize
54 | * 分片大小, 单位Byte
55 | * @throws ParamException
56 | */
57 | public static void AssertSliceInRange(int sliceSize) throws ParamException {
58 | int maxSliceSize = 10 * 1024 * 1024; // 10MB
59 | int minSliceSize = 64 * 1024; // 64KB
60 | if (sliceSize > maxSliceSize || sliceSize < minSliceSize) {
61 | throw new ParamException("sliceSize legal value is [64KB, 100MB]");
62 | }
63 | }
64 |
65 | private static void AssertNotContainIllegalLetter(String cosPath) throws ParamException {
66 | String[] illegalLetters = {"?", "*", ":", "|", "\\", "<", ">", "\""};
67 | for (String illegalLetter : illegalLetters) {
68 | if (cosPath.contains(illegalLetter)) {
69 | throw new ParamException("cosFilePath contail illeagl letter " + illegalLetter);
70 | }
71 | }
72 | String pattern = "/(\\s*)/";
73 | Pattern r = Pattern.compile(pattern);
74 | Matcher m = r.matcher(cosPath);
75 | if (m.find()) {
76 | throw new ParamException("cosFilePath contail illeagl letter / /");
77 | }
78 | }
79 |
80 | /**
81 | * 判断用户指定的cos目录路径是否合法有效, 即必须以/结尾, 同时不包含非法字符
82 | *
83 | * @param cosFolderPath
84 | * cos目录路径
85 | * @throws ParamException
86 | */
87 | public static void AssertLegalCosFolderPath(String cosFolderPath) throws ParamException {
88 | if (cosFolderPath == null || !cosFolderPath.startsWith("/") || !cosFolderPath.endsWith("/")) {
89 | throw new ParamException(cosFolderPath + " is not cos folder path! Tips: make sure ends with /");
90 | }
91 | AssertNotContainIllegalLetter(cosFolderPath);
92 | }
93 |
94 | /**
95 | * 判断用户指定的cos文件路径是否合法有效, 即不以/结尾
96 | *
97 | * @param cosFilePath
98 | * cos文件路径
99 | * @throws ParamException
100 | */
101 | public static void AssertLegalCosFilePath(String cosFilePath) throws ParamException {
102 | if (cosFilePath == null || !cosFilePath.startsWith("/") || cosFilePath.endsWith("/")) {
103 | throw new ParamException(cosFilePath + " is not cos file path! Tips: make sure not ends with /");
104 | }
105 | }
106 |
107 | /**
108 | * 判断cos目录是否是根路径,即路径为/
109 | *
110 | * @param cosCosFolderPath
111 | * cos目录路径
112 | * @throws ParamException
113 | */
114 | public static void AssertNotRootCosPath(String cosCosFolderPath) throws ParamException {
115 | if (cosCosFolderPath == null || cosCosFolderPath.equals("/")) {
116 | throw new ParamException(
117 | "bucket operation is only allowed by web console! please visit http://console.qcloud.com/cos!");
118 | }
119 | }
120 |
121 | /**
122 | * 判断用户指定的本地文件路径是否合法有效,即文件存在且可读
123 | *
124 | * @param localFilePath
125 | * 本地文件路径
126 | * @throws ParamException
127 | */
128 | public static void AssertLegalLocalFilePath(String localFilePath) throws ParamException {
129 | if (localFilePath == null || !CommonFileUtils.isLegalFile(localFilePath)) {
130 | throw new ParamException(localFilePath + " is not file or not exist or can't be read!");
131 | }
132 | }
133 |
134 | public static void AssertLegalXCosMeta(Map xCosMetaMap) throws ParamException {
135 | for (String x_cos_meta_key : xCosMetaMap.keySet()) {
136 | AssertNotNull("x_cos_meta_key", x_cos_meta_key);
137 | if (!x_cos_meta_key.startsWith("x-cos-meta-")) {
138 | throw new ParamException("x-cos-meta name must starts with x-cos-meta-");
139 | }
140 | String x_cos_meta_value = xCosMetaMap.get(x_cos_meta_key);
141 | AssertNotNull("x_cos_meta_value", x_cos_meta_value);
142 | if (x_cos_meta_value.isEmpty()) {
143 | throw new ParamException("x-cos-meta value can't be empty!");
144 | }
145 | }
146 |
147 | }
148 |
149 | public static void AssertLegalUpdateFlag(int updateFlag) throws ParamException {
150 | if (updateFlag == 0) {
151 | throw new ParamException("please update at least one attribute!");
152 | }
153 | }
154 |
155 | public static void AssertLegalSliceSize(int sliceSize) throws ParamException {
156 | if (sliceSize != 512 * 1024 && sliceSize != 1024 * 1024 && sliceSize != 2 * 1024 * 1024
157 | && sliceSize != 3 * 1024 * 1024) {
158 | throw new ParamException("valid slice is 512KB, 1MB, 2MB, 3MB");
159 | } else {
160 |
161 | }
162 | }
163 |
164 | }
165 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/common_utils/CommonPathUtils.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.common_utils;
2 |
3 | import java.io.UnsupportedEncodingException;
4 | import java.net.URLEncoder;
5 |
6 | import org.slf4j.Logger;
7 | import org.slf4j.LoggerFactory;
8 |
9 | import com.qcloud.cos.exception.AbstractCosException;
10 | import com.qcloud.cos.exception.UnknownException;
11 |
12 | public class CommonPathUtils {
13 | private static final Logger LOG = LoggerFactory.getLogger(CommonPathUtils.class);
14 | private static final String PATH_DELIMITER = "/";
15 |
16 | public static String encodeRemotePath(String urlPath) throws AbstractCosException {
17 | StringBuilder pathBuilder = new StringBuilder();
18 | String[] pathSegmentsArr = urlPath.split(PATH_DELIMITER);
19 |
20 | for (String pathSegment : pathSegmentsArr) {
21 | if (!pathSegment.isEmpty()) {
22 | try {
23 | pathBuilder.append(PATH_DELIMITER).append(URLEncoder.encode(pathSegment, "UTF-8").replace("+", "%20"));
24 | } catch (UnsupportedEncodingException e) {
25 | String errMsg = "Unsupported ecnode exception:" + e.toString();
26 | LOG.error(errMsg);
27 | throw new UnknownException(errMsg);
28 | }
29 | }
30 | }
31 | if (urlPath.endsWith(PATH_DELIMITER)) {
32 | pathBuilder.append(PATH_DELIMITER);
33 | }
34 | return pathBuilder.toString();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/common_utils/CommonSha1Utils.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.common_utils;
2 |
3 | /**
4 | * 求sha1, 未使用JAVA自带类,是为了获取分片的中间状态(state数组)
5 | * @author chengwu
6 | *
7 | */
8 | public final class CommonSha1Utils {
9 | private int state[] = new int[5];
10 | private long count;
11 | public byte[] digestBits;
12 | public boolean digestValid;
13 |
14 | public CommonSha1Utils() {
15 | state = new int[5];
16 | count = 0;
17 | if (block == null)
18 | block = new int[16];
19 | digestBits = new byte[20];
20 | digestValid = false;
21 | }
22 |
23 | /**
24 | * Add specific bytes to the digest.
25 | */
26 | public synchronized void update(byte input[], int offset, int len) {
27 | for (int i = 0; i < len; i++) {
28 | update(input[i + offset]);
29 | }
30 | }
31 |
32 | /**
33 | * Add an array of bytes to the digest.
34 | */
35 | public synchronized void update(byte input[]) {
36 | update(input, 0, input.length);
37 | }
38 |
39 | /**
40 | * Treat the string as a sequence of ISO-Latin1 (8 bit) characters.
41 | */
42 | public void updateASCII(String input) {
43 | int i, len;
44 | byte x;
45 |
46 | len = input.length();
47 | for (i = 0; i < len; i++) {
48 | x = (byte) (input.charAt(i) & 0xff);
49 | update(x);
50 | }
51 | }
52 |
53 | /*
54 | * The following array forms the basis for the transform buffer. Update puts bytes into this
55 | * buffer and then transform adds it into the state of the digest.
56 | */
57 | private int block[] = new int[16];
58 | private int blockIndex;
59 |
60 | /*
61 | * These functions are taken out of #defines in Steve's code. Java doesn't have a preprocessor
62 | * so the first step is to just promote them to real methods. Later we can optimize them out
63 | * into inline code, note that by making them final some compilers will inline them when given
64 | * the -O flag.
65 | */
66 | final int rol(int value, int bits) {
67 | int q = (value << bits) | (value >>> (32 - bits));
68 | return q;
69 | }
70 |
71 | final int blk0(int i) {
72 | block[i] = (rol(block[i], 24) & 0xFF00FF00) | (rol(block[i], 8) & 0x00FF00FF);
73 | return block[i];
74 | }
75 |
76 | final int blk(int i) {
77 | block[i & 15] = rol(block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15]
78 | ^ block[i & 15], 1);
79 | return (block[i & 15]);
80 | }
81 |
82 | final void R0(int data[], int v, int w, int x, int y, int z, int i) {
83 | data[z] += ((data[w] & (data[x] ^ data[y])) ^ data[y]) + blk0(i) + 0x5A827999
84 | + rol(data[v], 5);
85 | data[w] = rol(data[w], 30);
86 | }
87 |
88 | final void R1(int data[], int v, int w, int x, int y, int z, int i) {
89 | data[z] +=
90 | ((data[w] & (data[x] ^ data[y])) ^ data[y]) + blk(i) + 0x5A827999 + rol(data[v], 5);
91 | data[w] = rol(data[w], 30);
92 | }
93 |
94 | final void R2(int data[], int v, int w, int x, int y, int z, int i) {
95 | data[z] += (data[w] ^ data[x] ^ data[y]) + blk(i) + 0x6ED9EBA1 + rol(data[v], 5);
96 | data[w] = rol(data[w], 30);
97 | }
98 |
99 | final void R3(int data[], int v, int w, int x, int y, int z, int i) {
100 | data[z] += (((data[w] | data[x]) & data[y]) | (data[w] & data[x])) + blk(i) + 0x8F1BBCDC
101 | + rol(data[v], 5);
102 | data[w] = rol(data[w], 30);
103 | }
104 |
105 | final void R4(int data[], int v, int w, int x, int y, int z, int i) {
106 | data[z] += (data[w] ^ data[x] ^ data[y]) + blk(i) + 0xCA62C1D6 + rol(data[v], 5);
107 | data[w] = rol(data[w], 30);
108 | }
109 |
110 | int dd[] = new int[5];
111 |
112 | /**
113 | * Hash a single 512-bit block. This is the core of the algorithm.
114 | *
115 | * Note that working with arrays is very inefficent in Java as it does a class cast check each
116 | * time you store into the array.
117 | *
118 | */
119 |
120 | void transform() {
121 |
122 | /* Copy context->state[] to working vars */
123 | dd[0] = state[0];
124 | dd[1] = state[1];
125 | dd[2] = state[2];
126 | dd[3] = state[3];
127 | dd[4] = state[4];
128 | /* 4 rounds of 20 operations each. Loop unrolled. */
129 | R0(dd, 0, 1, 2, 3, 4, 0);
130 | R0(dd, 4, 0, 1, 2, 3, 1);
131 | R0(dd, 3, 4, 0, 1, 2, 2);
132 | R0(dd, 2, 3, 4, 0, 1, 3);
133 | R0(dd, 1, 2, 3, 4, 0, 4);
134 | R0(dd, 0, 1, 2, 3, 4, 5);
135 | R0(dd, 4, 0, 1, 2, 3, 6);
136 | R0(dd, 3, 4, 0, 1, 2, 7);
137 | R0(dd, 2, 3, 4, 0, 1, 8);
138 | R0(dd, 1, 2, 3, 4, 0, 9);
139 | R0(dd, 0, 1, 2, 3, 4, 10);
140 | R0(dd, 4, 0, 1, 2, 3, 11);
141 | R0(dd, 3, 4, 0, 1, 2, 12);
142 | R0(dd, 2, 3, 4, 0, 1, 13);
143 | R0(dd, 1, 2, 3, 4, 0, 14);
144 | R0(dd, 0, 1, 2, 3, 4, 15);
145 | R1(dd, 4, 0, 1, 2, 3, 16);
146 | R1(dd, 3, 4, 0, 1, 2, 17);
147 | R1(dd, 2, 3, 4, 0, 1, 18);
148 | R1(dd, 1, 2, 3, 4, 0, 19);
149 | R2(dd, 0, 1, 2, 3, 4, 20);
150 | R2(dd, 4, 0, 1, 2, 3, 21);
151 | R2(dd, 3, 4, 0, 1, 2, 22);
152 | R2(dd, 2, 3, 4, 0, 1, 23);
153 | R2(dd, 1, 2, 3, 4, 0, 24);
154 | R2(dd, 0, 1, 2, 3, 4, 25);
155 | R2(dd, 4, 0, 1, 2, 3, 26);
156 | R2(dd, 3, 4, 0, 1, 2, 27);
157 | R2(dd, 2, 3, 4, 0, 1, 28);
158 | R2(dd, 1, 2, 3, 4, 0, 29);
159 | R2(dd, 0, 1, 2, 3, 4, 30);
160 | R2(dd, 4, 0, 1, 2, 3, 31);
161 | R2(dd, 3, 4, 0, 1, 2, 32);
162 | R2(dd, 2, 3, 4, 0, 1, 33);
163 | R2(dd, 1, 2, 3, 4, 0, 34);
164 | R2(dd, 0, 1, 2, 3, 4, 35);
165 | R2(dd, 4, 0, 1, 2, 3, 36);
166 | R2(dd, 3, 4, 0, 1, 2, 37);
167 | R2(dd, 2, 3, 4, 0, 1, 38);
168 | R2(dd, 1, 2, 3, 4, 0, 39);
169 | R3(dd, 0, 1, 2, 3, 4, 40);
170 | R3(dd, 4, 0, 1, 2, 3, 41);
171 | R3(dd, 3, 4, 0, 1, 2, 42);
172 | R3(dd, 2, 3, 4, 0, 1, 43);
173 | R3(dd, 1, 2, 3, 4, 0, 44);
174 | R3(dd, 0, 1, 2, 3, 4, 45);
175 | R3(dd, 4, 0, 1, 2, 3, 46);
176 | R3(dd, 3, 4, 0, 1, 2, 47);
177 | R3(dd, 2, 3, 4, 0, 1, 48);
178 | R3(dd, 1, 2, 3, 4, 0, 49);
179 | R3(dd, 0, 1, 2, 3, 4, 50);
180 | R3(dd, 4, 0, 1, 2, 3, 51);
181 | R3(dd, 3, 4, 0, 1, 2, 52);
182 | R3(dd, 2, 3, 4, 0, 1, 53);
183 | R3(dd, 1, 2, 3, 4, 0, 54);
184 | R3(dd, 0, 1, 2, 3, 4, 55);
185 | R3(dd, 4, 0, 1, 2, 3, 56);
186 | R3(dd, 3, 4, 0, 1, 2, 57);
187 | R3(dd, 2, 3, 4, 0, 1, 58);
188 | R3(dd, 1, 2, 3, 4, 0, 59);
189 | R4(dd, 0, 1, 2, 3, 4, 60);
190 | R4(dd, 4, 0, 1, 2, 3, 61);
191 | R4(dd, 3, 4, 0, 1, 2, 62);
192 | R4(dd, 2, 3, 4, 0, 1, 63);
193 | R4(dd, 1, 2, 3, 4, 0, 64);
194 | R4(dd, 0, 1, 2, 3, 4, 65);
195 | R4(dd, 4, 0, 1, 2, 3, 66);
196 | R4(dd, 3, 4, 0, 1, 2, 67);
197 | R4(dd, 2, 3, 4, 0, 1, 68);
198 | R4(dd, 1, 2, 3, 4, 0, 69);
199 | R4(dd, 0, 1, 2, 3, 4, 70);
200 | R4(dd, 4, 0, 1, 2, 3, 71);
201 | R4(dd, 3, 4, 0, 1, 2, 72);
202 | R4(dd, 2, 3, 4, 0, 1, 73);
203 | R4(dd, 1, 2, 3, 4, 0, 74);
204 | R4(dd, 0, 1, 2, 3, 4, 75);
205 | R4(dd, 4, 0, 1, 2, 3, 76);
206 | R4(dd, 3, 4, 0, 1, 2, 77);
207 | R4(dd, 2, 3, 4, 0, 1, 78);
208 | R4(dd, 1, 2, 3, 4, 0, 79);
209 | /* Add the working vars back into context.state[] */
210 | state[0] += dd[0];
211 | state[1] += dd[1];
212 | state[2] += dd[2];
213 | state[3] += dd[3];
214 | state[4] += dd[4];
215 | }
216 |
217 |
218 | /**
219 | *
220 | * SHA1Init - Initialize new context
221 | */
222 | public void init() {
223 | /* SHA1 initialization constants */
224 | state[0] = 0x67452301;
225 | state[1] = 0xEFCDAB89;
226 | state[2] = 0x98BADCFE;
227 | state[3] = 0x10325476;
228 | state[4] = 0xC3D2E1F0;
229 | count = 0;
230 | digestBits = new byte[20];
231 | digestValid = false;
232 | blockIndex = 0;
233 | }
234 |
235 | /**
236 | * Add one byte to the digest. When this is implemented all of the abstract class methods end up
237 | * calling this method for types other than bytes.
238 | */
239 | public synchronized void update(byte b) {
240 | int mask = (8 * (blockIndex & 3));
241 |
242 | count += 8;
243 | block[blockIndex >> 2] &= ~(0xff << mask);
244 | block[blockIndex >> 2] |= (b & 0xff) << mask;
245 | blockIndex++;
246 | if (blockIndex == 64) {
247 | transform();
248 | blockIndex = 0;
249 | }
250 | }
251 |
252 |
253 | /**
254 | * Complete processing on the message digest.
255 | */
256 | public void finish() {
257 | byte bits[] = new byte[8];
258 | int i;
259 |
260 | for (i = 0; i < 8; i++) {
261 | bits[i] = (byte) ((count >>> (((7 - i) * 8))) & 0xff);
262 | }
263 |
264 | update((byte) 128);
265 | while (blockIndex != 56)
266 | update((byte) 0);
267 | // This should cause a transform to happen.
268 | update(bits);
269 | for (i = 0; i < 20; i++) {
270 | digestBits[i] = (byte) ((state[i >> 2] >> ((3 - (i & 3)) * 8)) & 0xff);
271 | }
272 | digestValid = true;
273 | }
274 |
275 | /** Return a string that identifies this algorithm */
276 | public String getAlg() {
277 | return "SHA1";
278 | }
279 |
280 | /**
281 | * Print out the digest in a form that can be easily compared to the test vectors.
282 | */
283 | public String digout() {
284 | StringBuffer sb = new StringBuffer();
285 | for (int i = 0; i < 20; i++) {
286 | char c1, c2;
287 |
288 | c1 = (char) ((digestBits[i] >>> 4) & 0xf);
289 | c2 = (char) (digestBits[i] & 0xf);
290 | c1 = (char) ((c1 > 9) ? 'a' + (c1 - 10) : '0' + c1);
291 | c2 = (char) ((c2 > 9) ? 'a' + (c2 - 10) : '0' + c2);
292 | sb.append(c1);
293 | sb.append(c2);
294 | /*
295 | * if (((i+1) % 4) == 0) sb.append(' ');
296 | */
297 | }
298 | return sb.toString();
299 | }
300 |
301 | // 输出中间状态
302 | public String dumpTempState() {
303 | StringBuilder sb = new StringBuilder();
304 | final int count = 5;
305 | for (int index = 0; index < count; ++index) {
306 | for (int i = 0; i < 4; ++i) {
307 | sb.append(String.format("%02x", (byte)(state[index] >>> (i * 8))));
308 | }
309 | }
310 | return sb.toString();
311 | }
312 | }
313 |
314 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/demo/Demo.java:
--------------------------------------------------------------------------------
1 | /*
2 | * To change this license header, choose License Headers in Project Properties. To change this
3 | * template file, choose Tools | Templates and open the template in the editor.
4 | */
5 | package com.qcloud.cos.demo;
6 |
7 | import java.nio.charset.Charset;
8 |
9 | import com.qcloud.cos.*;
10 | import com.qcloud.cos.common_utils.CommonFileUtils;
11 | import com.qcloud.cos.meta.FileAuthority;
12 | import com.qcloud.cos.meta.InsertOnly;
13 | import com.qcloud.cos.request.CreateFolderRequest;
14 | import com.qcloud.cos.request.DelFileRequest;
15 | import com.qcloud.cos.request.DelFolderRequest;
16 | import com.qcloud.cos.request.GetFileLocalRequest;
17 | import com.qcloud.cos.request.ListFolderRequest;
18 | import com.qcloud.cos.request.MoveFileRequest;
19 | import com.qcloud.cos.request.StatFileRequest;
20 | import com.qcloud.cos.request.StatFolderRequest;
21 | import com.qcloud.cos.request.UpdateFileRequest;
22 | import com.qcloud.cos.request.UpdateFolderRequest;
23 | import com.qcloud.cos.request.UploadFileRequest;
24 | import com.qcloud.cos.sign.Credentials;
25 |
26 |
27 | /**
28 | * @author chengwu cos Demo代码
29 | */
30 | public class Demo {
31 |
32 | public static void main(String[] args) throws Exception {
33 |
34 | // 设置用户属性, 包括appid, secretId和SecretKey
35 | // 这些属性可以通过cos控制台获取(https://console.qcloud.com/cos)
36 | long appId = 1000000;
37 | String secretId = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
38 | String secretKey = "xxxxxxxxxxxxxxxxxxxxxxxxxx";
39 | // 设置要操作的bucket
40 | String bucketName = "xxxxxxxxx";
41 | // 初始化客户端配置
42 | ClientConfig clientConfig = new ClientConfig();
43 | // 设置bucket所在的区域,比如广州(gz), 天津(tj)
44 | clientConfig.setRegion("gz");
45 | // 初始化秘钥信息
46 | Credentials cred = new Credentials(appId, secretId, secretKey);
47 | // 初始化cosClient
48 | COSClient cosClient = new COSClient(clientConfig, cred);
49 | ///////////////////////////////////////////////////////////////
50 | // 文件操作 //
51 | ///////////////////////////////////////////////////////////////
52 | // 1. 上传文件(将本地文件上传到COS)
53 | // 将本地的local_file_1.txt上传到bucket下的根分区下,并命名为sample_file.txt
54 | // 默认不覆盖, 如果cos上已有文件, 则返回错误
55 | String cosFilePath = "/sample_file.txt";
56 | String localFilePath1 = "src/test/resources/bigfile.txt";
57 | UploadFileRequest uploadFileRequest =
58 | new UploadFileRequest(bucketName, cosFilePath, localFilePath1);
59 | uploadFileRequest.setEnableShaDigest(false);
60 | String uploadFileRet = cosClient.uploadFile(uploadFileRequest);
61 | System.out.println("upload file ret:" + uploadFileRet);
62 |
63 | // 2. 下载文件
64 | String localPathDown = "src/test/resources/local_file_down.txt";
65 | GetFileLocalRequest getFileLocalRequest =
66 | new GetFileLocalRequest(bucketName, cosFilePath, localPathDown);
67 | getFileLocalRequest.setUseCDN(false);
68 | getFileLocalRequest.setReferer("*.myweb.cn");
69 | String getFileResult = cosClient.getFileLocal(getFileLocalRequest);
70 | System.out.println("getFileResult:" + getFileResult);
71 |
72 | // 3. 上传文件(将内存数据上传到COS)
73 | // 示例程序的内存数据来自于本地文件,将本地文件整体读入内存,如果本地文件过大,可能导致OOM
74 | // 因此如果数据在本地,建议直接用方法1
75 | String localFilePath2 = "src/test/resources/local_file_2.txt";
76 | byte[] contentBuffer = CommonFileUtils.getFileContent(localFilePath2)
77 | .getBytes(Charset.forName(("ISO-8859-1")));
78 | UploadFileRequest overWriteFileRequest =
79 | new UploadFileRequest(bucketName, cosFilePath, contentBuffer);
80 | String overWriteFileRet = cosClient.uploadFile(overWriteFileRequest);
81 | System.out.println("overwrite file ret:" + overWriteFileRet);
82 |
83 | // 4. 获取文件属性
84 | StatFileRequest statFileRequest = new StatFileRequest(bucketName, cosFilePath);
85 | String statFileRet = cosClient.statFile(statFileRequest);
86 | System.out.println("stat file ret:" + statFileRet);
87 |
88 | // 5. 更新文件属性
89 | UpdateFileRequest updateFileRequest = new UpdateFileRequest(bucketName, cosFilePath);
90 | updateFileRequest.setBizAttr("测试目录");
91 | updateFileRequest.setAuthority(FileAuthority.WPRIVATE);
92 | updateFileRequest.setCacheControl("no cache");
93 | updateFileRequest.setContentDisposition("cos_sample.txt");
94 | updateFileRequest.setContentLanguage("english");
95 | updateFileRequest.setContentType("application/json");
96 | updateFileRequest.setXCosMeta("x-cos-meta-xxx", "xxx");
97 | updateFileRequest.setXCosMeta("x-cos-meta-yyy", "yyy");
98 | updateFileRequest.setContentEncoding("gzip");
99 | String updateFileRet = cosClient.updateFile(updateFileRequest);
100 | System.out.println("update file ret:" + updateFileRet);
101 |
102 | // 6. 更新文件后再次获取属性
103 | statFileRet = cosClient.statFile(statFileRequest);
104 | System.out.println("stat file ret:" + statFileRet);
105 |
106 | // 6.1 move文件,从/sample_file.txt移动为./sample_file.txt.bak
107 | String dstFilePath = cosFilePath + ".bak";
108 | MoveFileRequest moveRequest = new MoveFileRequest(bucketName, cosFilePath, dstFilePath);
109 | String moveFileRet = cosClient.moveFile(moveRequest);
110 | System.out.println("first move file ret:" + moveFileRet);
111 | // 6.2 在从/sample_file.txt.bak移动为/sample_file.txt
112 | moveRequest = new MoveFileRequest(bucketName, dstFilePath, cosFilePath);
113 | moveFileRet = cosClient.moveFile(moveRequest);
114 | System.out.println("second move file ret:" + moveFileRet);
115 |
116 | // 7. 删除文件
117 | DelFileRequest delFileRequest = new DelFileRequest(bucketName, cosFilePath);
118 | String delFileRet = cosClient.delFile(delFileRequest);
119 | System.out.println("del file ret:" + delFileRet);
120 |
121 | ///////////////////////////////////////////////////////////////
122 | // 目录操作 //
123 | ///////////////////////////////////////////////////////////////
124 | // 1. 生成目录, 目录名为sample_folder
125 | String cosFolderPath = "/xxsample_folder/";
126 | CreateFolderRequest createFolderRequest =
127 | new CreateFolderRequest(bucketName, cosFolderPath);
128 | String createFolderRet = cosClient.createFolder(createFolderRequest);
129 | System.out.println("create folder ret:" + createFolderRet);
130 |
131 | // 2. 更新目录的biz_attr属性
132 | UpdateFolderRequest updateFolderRequest =
133 | new UpdateFolderRequest(bucketName, cosFolderPath);
134 | updateFolderRequest.setBizAttr("这是一个测试目录");
135 | String updateFolderRet = cosClient.updateFolder(updateFolderRequest);
136 | System.out.println("update folder ret:" + updateFolderRet);
137 |
138 | // 3. 获取目录属性
139 | StatFolderRequest statFolderRequest = new StatFolderRequest(bucketName, cosFolderPath);
140 | String statFolderRet = cosClient.statFolder(statFolderRequest);
141 | System.out.println("stat folder ret:" + statFolderRet);
142 |
143 | // 4. list目录, 获取目录下的成员
144 | ListFolderRequest listFolderRequest = new ListFolderRequest(bucketName, cosFolderPath);
145 | String listFolderRet = cosClient.listFolder(listFolderRequest);
146 | System.out.println("list folder ret:" + listFolderRet);
147 |
148 | // 5. 删除目录
149 | DelFolderRequest delFolderRequest = new DelFolderRequest(bucketName, cosFolderPath);
150 | String delFolderRet = cosClient.delFolder(delFolderRequest);
151 | System.out.println("del folder ret:" + delFolderRet);
152 |
153 | // 关闭释放资源
154 | cosClient.shutdown();
155 | System.out.println("shutdown!");
156 |
157 | }
158 | }
159 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/exception/AbstractCosException.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.exception;
2 |
3 | import org.json.JSONObject;
4 |
5 | import com.qcloud.cos.http.ResponseBodyKey;
6 |
7 | /**
8 | * 封装cos异常
9 | * @author chengwu
10 | *
11 | */
12 | public abstract class AbstractCosException extends Exception {
13 |
14 | private static final long serialVersionUID = 7547532865194837136L;
15 |
16 | private CosExceptionType type;
17 |
18 | public AbstractCosException(CosExceptionType type, String message) {
19 | super(message);
20 | this.type = type;
21 | }
22 |
23 | public CosExceptionType getType() {
24 | return type;
25 | }
26 |
27 | @Override
28 | public String toString() {
29 | JSONObject responseObj = new JSONObject();
30 | responseObj.put(ResponseBodyKey.CODE, type.getErrorCode());
31 | responseObj.put(ResponseBodyKey.MESSAGE, getMessage());
32 | return responseObj.toString();
33 | }
34 |
35 | }
36 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/exception/CosExceptionType.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.exception;
2 |
3 | import com.qcloud.cos.ErrorCode;
4 |
5 | // 枚举cos异常类型
6 | public enum CosExceptionType {
7 | // 参数异常
8 | PARAM_EXCEPTION(ErrorCode.PARAMS_ERROR, "param_excepiton"),
9 | // 网络异常
10 | NETWORK_EXCEPITON(ErrorCode.NETWORK_ERROR, "network_excepiton"),
11 | // 服务端异常
12 | SERVER_EXCEPTION(ErrorCode.SERVER_ERROR, "server_exception"),
13 | // 其他未知异常
14 | UNKNOWN_EXCEPTION(ErrorCode.UNKNOWN_ERROR, "unknown_exception");
15 |
16 | private int errorCode;
17 | private String exceptionStr;
18 |
19 | private CosExceptionType(int errorCode, String exceptionStr) {
20 | this.errorCode = errorCode;
21 | this.exceptionStr = exceptionStr;
22 | }
23 |
24 | public int getErrorCode() {
25 | return errorCode;
26 | }
27 |
28 | public String getExceptionStr() {
29 | return exceptionStr;
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/exception/NetworkException.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.exception;
2 |
3 | // 网络异常(如网络故障,导致无法连接服务端)
4 | public class NetworkException extends AbstractCosException {
5 |
6 | private static final long serialVersionUID = -6662661467437143397L;
7 |
8 | public NetworkException(String message) {
9 | super(CosExceptionType.NETWORK_EXCEPITON, message);
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/exception/ParamException.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.exception;
2 |
3 | // 参数异常
4 | public class ParamException extends AbstractCosException {
5 |
6 | private static final long serialVersionUID = 216921496331691543L;
7 |
8 | public ParamException(String message) {
9 | super(CosExceptionType.PARAM_EXCEPTION, message);
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/exception/ServerException.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.exception;
2 |
3 | // 服务端异常(如返回404deng)
4 | public class ServerException extends AbstractCosException {
5 |
6 | private static final long serialVersionUID = -4536038808919814914L;
7 |
8 | public ServerException(String message) {
9 | super(CosExceptionType.SERVER_EXCEPTION, message);
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/exception/UnknownException.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.exception;
2 |
3 | // 未知异常
4 | public class UnknownException extends AbstractCosException {
5 |
6 | private static final long serialVersionUID = 4303770859616883146L;
7 |
8 | public UnknownException(String message) {
9 | super(CosExceptionType.UNKNOWN_EXCEPTION, message);
10 | }
11 |
12 | }
13 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/AbstractCosHttpClient.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 |
3 | import java.io.InputStream;
4 |
5 | import org.apache.http.HttpHost;
6 | import org.apache.http.client.HttpClient;
7 | import org.apache.http.client.config.RequestConfig;
8 | import org.apache.http.impl.client.HttpClientBuilder;
9 | import org.apache.http.impl.client.HttpClients;
10 | import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
11 |
12 | import com.qcloud.cos.ClientConfig;
13 | import com.qcloud.cos.exception.AbstractCosException;
14 | import com.qcloud.cos.exception.ParamException;
15 |
16 | public abstract class AbstractCosHttpClient {
17 | protected ClientConfig config;
18 | protected HttpClient httpClient;
19 |
20 | protected PoolingHttpClientConnectionManager connectionManager;
21 | protected IdleConnectionMonitorThread idleConnectionMonitor;
22 |
23 | protected RequestConfig requestConfig;
24 |
25 | public AbstractCosHttpClient(ClientConfig config) {
26 | super();
27 | this.config = config;
28 | this.connectionManager = new PoolingHttpClientConnectionManager();
29 | this.connectionManager.setMaxTotal(config.getMaxConnectionsCount());
30 | this.connectionManager.setDefaultMaxPerRoute(config.getMaxConnectionsCount());
31 | this.connectionManager.setValidateAfterInactivity(1);
32 | HttpClientBuilder httpClientBuilder =
33 | HttpClients.custom().setConnectionManager(connectionManager);
34 | if (config.getHttpProxyIp() != null && config.getHttpProxyPort() != 0) {
35 | HttpHost proxy = new HttpHost(config.getHttpProxyIp(), config.getHttpProxyPort());
36 | httpClientBuilder.setProxy(proxy);
37 | }
38 | this.httpClient = httpClientBuilder.build();
39 | this.requestConfig = RequestConfig.custom()
40 | .setConnectionRequestTimeout(this.config.getConnectionRequestTimeout())
41 | .setConnectTimeout(this.config.getConnectionTimeout())
42 | .setSocketTimeout(this.config.getSocketTimeout()).build();
43 | this.idleConnectionMonitor = new IdleConnectionMonitorThread(this.connectionManager);
44 | this.idleConnectionMonitor.setDaemon(true);
45 | this.idleConnectionMonitor.start();
46 | }
47 |
48 | protected abstract String sendPostRequest(HttpRequest httpRequest) throws AbstractCosException;
49 |
50 | protected abstract String sendGetRequest(HttpRequest httpRequest) throws AbstractCosException;
51 |
52 | public String sendHttpRequest(HttpRequest httpRequest) throws AbstractCosException {
53 |
54 | HttpMethod method = httpRequest.getMethod();
55 | if (method == HttpMethod.POST) {
56 | return sendPostRequest(httpRequest);
57 | } else if (method == HttpMethod.GET) {
58 | return sendGetRequest(httpRequest);
59 | } else {
60 | throw new ParamException("Unsupported Http Method");
61 | }
62 | }
63 |
64 | public abstract InputStream getFileInputStream(HttpRequest httpRequest)
65 | throws AbstractCosException;
66 |
67 | public void shutdown() {
68 | this.idleConnectionMonitor.shutdown();
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/DefaultCosHttpClient.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 | import java.net.URISyntaxException;
6 | import java.nio.charset.Charset;
7 | import java.util.Map;
8 |
9 | import org.apache.http.Consts;
10 | import org.apache.http.HttpEntity;
11 | import org.apache.http.HttpMessage;
12 | import org.apache.http.HttpResponse;
13 | import org.apache.http.ParseException;
14 | import org.apache.http.client.methods.HttpGet;
15 | import org.apache.http.client.methods.HttpPost;
16 | import org.apache.http.client.utils.URIBuilder;
17 | import org.apache.http.entity.ContentType;
18 | import org.apache.http.entity.StringEntity;
19 | import org.apache.http.entity.mime.MultipartEntityBuilder;
20 | import org.apache.http.util.EntityUtils;
21 | import org.json.JSONException;
22 | import org.json.JSONObject;
23 | import org.slf4j.Logger;
24 | import org.slf4j.LoggerFactory;
25 |
26 | import com.qcloud.cos.ClientConfig;
27 | import com.qcloud.cos.exception.AbstractCosException;
28 | import com.qcloud.cos.exception.ParamException;
29 | import com.qcloud.cos.exception.ServerException;
30 | import com.qcloud.cos.exception.UnknownException;
31 | import com.qcloud.cos.meta.COSObjectInputStream;
32 |
33 | /**
34 | * @author chengwu 封装Http发送请求类
35 | */
36 | public class DefaultCosHttpClient extends AbstractCosHttpClient {
37 |
38 | private static final Logger LOG = LoggerFactory.getLogger(DefaultCosHttpClient.class);
39 |
40 | public DefaultCosHttpClient(ClientConfig config) {
41 | super(config);
42 | }
43 |
44 | // 获得异常发生时的返回信息
45 | private String getExceptionMsg(HttpRequest httpRequest, String exceptionStr) {
46 | String errMsg = new StringBuilder("HttpRequest:").append(httpRequest.toString())
47 | .append("\nException:").append(exceptionStr).toString();
48 | LOG.error(errMsg);
49 | return errMsg;
50 | }
51 |
52 | /**
53 | * Get请求函数
54 | *
55 | * @param url
56 | * @param headers 额外添加的Http头部
57 | * @param params GET请求的参数
58 | * @return Cos服务器返回的字符串
59 | * @throws Exception
60 | */
61 | @Override
62 | protected String sendGetRequest(HttpRequest httpRequest) throws AbstractCosException {
63 | String url = httpRequest.getUrl();
64 | HttpGet httpGet = null;
65 | String responseStr = "";
66 | int retry = 0;
67 | int maxRetryCount = this.config.getMaxFailedRetry();
68 | while (retry < maxRetryCount) {
69 | try {
70 | URIBuilder urlBuilder = new URIBuilder(url);
71 | for (String paramKey : httpRequest.getParams().keySet()) {
72 | urlBuilder.addParameter(paramKey, httpRequest.getParams().get(paramKey));
73 | }
74 | httpGet = new HttpGet(urlBuilder.build());
75 | } catch (URISyntaxException e) {
76 | String errMsg = "Invalid url:" + url;
77 | LOG.error(errMsg);
78 | throw new ParamException(errMsg);
79 | }
80 |
81 | httpGet.setConfig(requestConfig);
82 | setHeaders(httpGet, httpRequest.getHeaders());
83 |
84 | HttpResponse httpResponse = null;
85 | try {
86 | httpResponse = httpClient.execute(httpGet);
87 | int http_statuscode = httpResponse.getStatusLine().getStatusCode();
88 |
89 | if (http_statuscode >= 500 && http_statuscode <= 599) {
90 | String errMsg = String.format("http status code is %d, response body: %s",
91 | http_statuscode, getResponseString(httpResponse));
92 | throw new IOException(errMsg);
93 | }
94 |
95 | responseStr = getResponseString(httpResponse);
96 | new JSONObject(responseStr);
97 | httpGet.releaseConnection();
98 | return responseStr;
99 | } catch (ParseException e) {
100 | httpGet.abort();
101 | ++retry;
102 | if (retry == maxRetryCount) {
103 | String errMsg = getExceptionMsg(httpRequest, e.toString());
104 | throw new ServerException(errMsg);
105 | }
106 | } catch (IOException e) {
107 | httpGet.abort();
108 | ++retry;
109 | if (retry == maxRetryCount) {
110 | String errMsg = getExceptionMsg(httpRequest, e.toString());
111 | throw new ServerException(errMsg);
112 | }
113 | } catch (JSONException e) {
114 | httpGet.abort();
115 | String errMsg = String.format(
116 | "server response is not json, httpRequest: %s, httpResponse: %s, responseStr: %s",
117 | httpRequest.toString(), httpResponse.toString(), responseStr);
118 | throw new ServerException(errMsg);
119 | }
120 | }
121 | return responseStr;
122 |
123 | }
124 |
125 | @Override
126 | protected String sendPostRequest(HttpRequest httpRequest) throws AbstractCosException {
127 | String url = httpRequest.getUrl();
128 | String responseStr = "";
129 | int retry = 0;
130 | int maxRetryCount = this.config.getMaxFailedRetry();
131 | while (retry < maxRetryCount) {
132 | HttpPost httpPost = new HttpPost(url);
133 | httpPost.setConfig(requestConfig);
134 |
135 | Map params = httpRequest.getParams();
136 | setHeaders(httpPost, httpRequest.getHeaders());
137 |
138 | if (httpRequest.getContentType() == HttpContentType.APPLICATION_JSON) {
139 | setJsonEntity(httpPost, params);
140 | } else if (httpRequest.getContentType() == HttpContentType.MULTIPART_FORM_DATA) {
141 | try {
142 | setMultiPartEntity(httpPost, params);
143 | } catch (Exception e) {
144 | throw new UnknownException(e.toString());
145 | }
146 | }
147 |
148 | HttpResponse httpResponse = null;
149 | try {
150 | httpResponse = httpClient.execute(httpPost);
151 | int http_statuscode = httpResponse.getStatusLine().getStatusCode();
152 | if (http_statuscode >= 500 && http_statuscode <= 599) {
153 | String errMsg = String.format("http status code is %d, response body: %s",
154 | http_statuscode, getResponseString(httpResponse));
155 | throw new IOException(errMsg);
156 | }
157 | responseStr = getResponseString(httpResponse);
158 | new JSONObject(responseStr);
159 | httpPost.releaseConnection();
160 | return responseStr;
161 | } catch (ParseException e) {
162 | httpPost.abort();
163 | ++retry;
164 | if (retry == maxRetryCount) {
165 | String errMsg = getExceptionMsg(httpRequest, e.toString());
166 | throw new ServerException(errMsg);
167 | }
168 | } catch (IOException e) {
169 | httpPost.abort();
170 | ++retry;
171 | if (retry == maxRetryCount) {
172 | String errMsg = getExceptionMsg(httpRequest, e.toString());
173 | throw new ServerException(errMsg);
174 | }
175 | } catch (JSONException e) {
176 | httpPost.abort();
177 | String errMsg = String.format(
178 | "server response is not json, httpRequest: %s, httpResponse: %s, responseStr: %s",
179 | httpRequest.toString(), httpResponse.toString(), responseStr);
180 | throw new ServerException(errMsg);
181 | }
182 | }
183 | return responseStr;
184 | }
185 |
186 | @Override
187 | public InputStream getFileInputStream(HttpRequest httpRequest) throws AbstractCosException {
188 | String url = httpRequest.getUrl();
189 | int retry = 0;
190 | int maxRetryCount = this.config.getMaxFailedRetry();
191 | while (retry < maxRetryCount) {
192 | HttpGet httpGet = null;
193 | try {
194 | URIBuilder urlBuilder = new URIBuilder(url);
195 | for (String paramKey : httpRequest.getParams().keySet()) {
196 | urlBuilder.addParameter(paramKey, httpRequest.getParams().get(paramKey));
197 | }
198 | httpGet = new HttpGet(urlBuilder.build());
199 | } catch (URISyntaxException e) {
200 | String errMsg = "Invalid url:" + url;
201 | LOG.error(errMsg);
202 | throw new ParamException(errMsg);
203 | }
204 |
205 | httpGet.setConfig(requestConfig);
206 | setHeaders(httpGet, httpRequest.getHeaders());
207 | try {
208 | HttpResponse httpResponse = httpClient.execute(httpGet);
209 | int http_statuscode = httpResponse.getStatusLine().getStatusCode();
210 | if (http_statuscode >= 500 && http_statuscode <= 599) {
211 | String errMsg = String.format("http status code is %d, response body: %s",
212 | http_statuscode, getResponseString(httpResponse));
213 | throw new IOException(errMsg);
214 | }
215 | if (http_statuscode != 200 && http_statuscode != 206) {
216 | String responseStr = getResponseString(httpResponse);
217 | String errMsg = String.format(
218 | "getFileinputstream failed, httpRequest: %s, httpResponse: %s, responseStr: %s",
219 | httpRequest.toString(), httpResponse.toString(), responseStr);
220 |
221 | httpGet.releaseConnection();
222 | throw new ServerException(errMsg);
223 | }
224 | HttpEntity entity = httpResponse.getEntity();
225 | COSObjectInputStream cosObjectInputStream =
226 | new COSObjectInputStream(entity.getContent(), httpGet);
227 | return cosObjectInputStream;
228 | } catch (ParseException e) {
229 | ++retry;
230 | httpGet.abort();
231 | if (retry == maxRetryCount) {
232 | String errMsg = getExceptionMsg(httpRequest, e.toString());
233 | throw new ServerException(errMsg);
234 | }
235 | } catch (IOException e) {
236 | ++retry;
237 | httpGet.abort();
238 | if (retry == maxRetryCount) {
239 | String errMsg = getExceptionMsg(httpRequest, e.toString());
240 | throw new ServerException(errMsg);
241 | }
242 | }
243 | }
244 | // never will reach here
245 | return null;
246 | }
247 |
248 | private String getResponseString(HttpResponse httpResponse) throws ParseException, IOException {
249 | String httpResponseStr = null;
250 | HttpEntity httpEntity = httpResponse.getEntity();
251 | if (httpEntity != null) {
252 | httpResponseStr = EntityUtils.toString(httpEntity, "UTF-8");
253 | }
254 |
255 | if (httpResponseStr == null) {
256 | return "";
257 | } else {
258 | return httpResponseStr;
259 | }
260 | }
261 |
262 | private void setJsonEntity(HttpPost httpPost, Map params) {
263 | ContentType utf8TextPlain = ContentType.create("text/plain", Consts.UTF_8);
264 | String postJsonStr = new JSONObject(params).toString();
265 | StringEntity stringEntity = new StringEntity(postJsonStr, utf8TextPlain);
266 | httpPost.setEntity(stringEntity);
267 | }
268 |
269 | private void setMultiPartEntity(HttpPost httpPost, Map params)
270 | throws Exception {
271 | ContentType utf8TextPlain = ContentType.create("text/plain", Consts.UTF_8);
272 | MultipartEntityBuilder entityBuilder = MultipartEntityBuilder.create();
273 | for (String paramKey : params.keySet()) {
274 | if (paramKey.equals(RequestBodyKey.FILE_CONTENT)) {
275 | entityBuilder.addBinaryBody(RequestBodyKey.FILE_CONTENT, params
276 | .get(RequestBodyKey.FILE_CONTENT).getBytes(Charset.forName("ISO-8859-1")));
277 | } else {
278 | entityBuilder.addTextBody(paramKey, params.get(paramKey), utf8TextPlain);
279 | }
280 | }
281 | httpPost.setEntity(entityBuilder.build());
282 | }
283 |
284 | /**
285 | * 设置Http头部,同时添加上公共的类型,长连接,COS SDK标识
286 | *
287 | * @param message HTTP消息
288 | * @param headers 用户额外添加的HTTP头部
289 | */
290 | private void setHeaders(HttpMessage message, Map headers) {
291 | message.setHeader(RequestHeaderKey.ACCEPT, RequestHeaderValue.Accept.ALL);
292 | message.setHeader(RequestHeaderKey.CONNECTION, RequestHeaderValue.Connection.KEEP_ALIVE);
293 | message.setHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
294 |
295 | if (headers != null) {
296 | for (String headerKey : headers.keySet()) {
297 | message.setHeader(headerKey, headers.get(headerKey));
298 | }
299 | }
300 | }
301 |
302 | }
303 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/HttpContentType.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 |
3 | public enum HttpContentType {
4 |
5 | APPLICATION_JSON("application/json"),
6 |
7 | MULTIPART_FORM_DATA("multipart/form-data");
8 |
9 | private String contentType;
10 |
11 | private HttpContentType(String contentType) {
12 | this.contentType = contentType;
13 | }
14 |
15 | @Override
16 | public String toString() {
17 | return this.contentType;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/HttpMethod.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 |
3 | public enum HttpMethod {
4 |
5 | GET("GET"),
6 |
7 | POST("POST"),
8 |
9 | PUT("PUT"),
10 |
11 | DELETE("DELETE");
12 |
13 | private String method;
14 |
15 | private HttpMethod(String method) {
16 | this.method = method;
17 | }
18 |
19 | @Override
20 | public String toString() {
21 | return this.method;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/HttpRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 |
3 | import java.util.LinkedHashMap;
4 | import java.util.Map;
5 | import java.util.Map.Entry;
6 |
7 | public class HttpRequest {
8 | private String url = "";
9 | private HttpMethod method = HttpMethod.POST;
10 | private HttpContentType contentType = HttpContentType.MULTIPART_FORM_DATA;
11 | private Map headers = new LinkedHashMap();
12 | private Map params = new LinkedHashMap();
13 |
14 | public HttpRequest() {
15 | super();
16 | }
17 |
18 | public String getUrl() {
19 | return url;
20 | }
21 |
22 | public void setUrl(String url) {
23 | this.url = url;
24 | }
25 |
26 | public HttpMethod getMethod() {
27 | return method;
28 | }
29 |
30 | public void setMethod(HttpMethod method) {
31 | this.method = method;
32 | }
33 |
34 | public HttpContentType getContentType() {
35 | return contentType;
36 | }
37 |
38 | public void setContentType(HttpContentType contentType) {
39 | this.contentType = contentType;
40 | }
41 |
42 | public Map getHeaders() {
43 | return headers;
44 | }
45 |
46 | public Map getParams() {
47 | return params;
48 | }
49 |
50 | public void addHeader(String key, String value) {
51 | this.headers.put(key, value);
52 | }
53 |
54 | public void addParam(String key, String value) {
55 | this.params.put(key, value);
56 | }
57 |
58 | @Override
59 | public String toString() {
60 | StringBuilder sb = new StringBuilder();
61 | sb.append("url:").append(url).append(", method:").append(method).append(", ConentType:")
62 | .append(contentType.toString()).append("\n");
63 |
64 | sb.append("Headers:\n");
65 | for (Entry entry : headers.entrySet()) {
66 | sb.append("key:").append(entry.getKey());
67 | sb.append(", value:").append(entry.getValue());
68 | sb.append("\n");
69 | }
70 |
71 | sb.append("params:\n");
72 | for (Entry entry : params.entrySet()) {
73 | if (entry.getKey().equals(RequestBodyKey.FILE_CONTENT)) {
74 | continue;
75 | }
76 | sb.append("key:").append(entry.getKey());
77 | sb.append(", value:").append(entry.getValue());
78 | sb.append("\n");
79 | }
80 |
81 | return sb.toString();
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/IdleConnectionMonitorThread.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 |
3 | import java.util.concurrent.TimeUnit;
4 |
5 | import org.apache.http.conn.HttpClientConnectionManager;
6 |
7 | // 用于监控空闲的连接池连接
8 | public final class IdleConnectionMonitorThread extends Thread {
9 | private final HttpClientConnectionManager connMgr;
10 | private volatile boolean shutdown;
11 |
12 | private static final int MONITOR_INTERVAL_MS = 2000;
13 | private static final int IDLE_ALIVE_MS = 5000;
14 |
15 | public IdleConnectionMonitorThread(HttpClientConnectionManager connMgr) {
16 | super();
17 | this.connMgr = connMgr;
18 | this.shutdown = false;
19 | }
20 |
21 | @Override
22 | public void run() {
23 | try {
24 | while (!shutdown) {
25 | synchronized (this) {
26 | wait(MONITOR_INTERVAL_MS);
27 | // 关闭无效的连接
28 | connMgr.closeExpiredConnections();
29 | // 关闭空闲时间超过IDLE_ALIVE_MS的连接
30 | connMgr.closeIdleConnections(IDLE_ALIVE_MS, TimeUnit.MILLISECONDS);
31 | }
32 | }
33 | } catch (InterruptedException e) {
34 |
35 | }
36 | }
37 |
38 | // 关闭后台连接
39 | public void shutdown() {
40 | shutdown = true;
41 | synchronized (this) {
42 | notifyAll();
43 | }
44 | }
45 |
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/RequestBodyKey.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 |
3 | /**
4 | * @author chengwu 封装HTTP请求包体中的K-V对中key枚举值类
5 | */
6 | public class RequestBodyKey {
7 | public static final String OP = "op";
8 | public static final String BIZ_ATTR = "biz_attr";
9 | public static final String UPDATE_FLAG = "flag";
10 | public static final String AUTHORITY = "authority";
11 | public static final String CUSTOM_HEADERS = "custom_headers";
12 | public static final String INSERT_ONLY = "insertOnly";
13 | public static final String DEST_FIELD = "dest_fileid";
14 | public static final String TO_OVER_WRITE = "to_over_write";
15 | public static final String PREFIX = "prefix";
16 | public static final String NUM = "num";
17 | public static final String CONTEXT = "context";
18 | public static final String LIST_FLAG = "list_flag";
19 | public static final String DELIMITER = "delimiter";
20 | public static final String SHA = "sha";
21 | public static final String FILE_CONTENT = "fileContent";
22 | public static final String FILE_SIZE = "filesize";
23 | public static final String SLICE_SIZE = "slice_size";
24 | public static final String SESSION = "session";
25 | public static final String OFFSET = "offset";
26 | public static final String UPLOAD_PARTS = "uploadparts";
27 |
28 | public class UploadParts {
29 | public static final String OFFSET = "offset";
30 | public static final String DATA_LEN = "datalen";
31 | public static final String DATA_SHA = "datasha";
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/RequestBodyValue.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 | /**
3 | * @author chengwu
4 | * 封装HTTP请求包体的k-v对中的value枚举值类
5 | */
6 | public class RequestBodyValue {
7 | public class OP {
8 | public static final String CREATE = "create";
9 | public static final String LIST = "list";
10 | public static final String UPDATE = "update";
11 | public static final String STAT = "stat";
12 | public static final String MOVE = "move";
13 | public static final String DELETE = "delete";
14 | public static final String UPLOAD = "upload";
15 | public static final String UPLOAD_SLICE_INIT = "upload_slice_init";
16 | public static final String UPLOAD_SLICE_DATA = "upload_slice_data";
17 | public static final String UPLOAD_SLICE_FINISH = "upload_slice_finish";
18 | public static final String UPLOAD_SLICE_LIST = "upload_slice_list";
19 | }
20 |
21 | }
22 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/RequestHeaderKey.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 | /**
3 | * @author chengwu
4 | * 封装HTTP请求头中的对应的K-V对中key枚举值类
5 | */
6 | public class RequestHeaderKey {
7 | public static final String Authorization = "Authorization";
8 | public static final String Content_TYPE = "Content-Type";
9 | public static final String ACCEPT = "Accept";
10 | public static final String CONNECTION = "Connection";
11 | public static final String USER_AGENT = "User-Agent";
12 | public static final String RANGE = "Range";
13 | public static final String SIGN = "sign";
14 | public static final String REFERER = "Referer";
15 | }
16 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/RequestHeaderValue.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 | /**
3 | * @author chengwu
4 | * 封装HTTP请求头中的对应的K-V对中value枚举值类
5 | */
6 |
7 | public class RequestHeaderValue {
8 | public static class Method {
9 | public static final String POST = "POST";
10 | public static final String GET = "GET";
11 | public static final String PUT = "PUT";
12 | public static final String DELETE = "DELETE";
13 | }
14 |
15 | public static class ContentType {
16 | public static final String JSON = "application/json";
17 | public static final String FORM_DATA = "multipart/form-data";
18 | }
19 |
20 | public static class Accept {
21 | public static final String ALL = "*/*";
22 | }
23 |
24 | public static class UserAgent {
25 | public static final String COS_FLAG = "qcloud-java-sdk";
26 | }
27 |
28 | public static class Connection {
29 | public static final String KEEP_ALIVE = "Keep-Alive";
30 | }
31 |
32 | }
33 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/http/ResponseBodyKey.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.http;
2 |
3 | /**
4 | * @author chengwu
5 | * 封装服务器端返回的应答包体的关键字枚举类
6 | */
7 | public class ResponseBodyKey {
8 | public static final String CODE = "code";
9 | public static final String MESSAGE = "message";
10 | public static final String DATA = "data";
11 |
12 | public class Data {
13 | public static final String SESSION = "session";
14 | public static final String OFFSET = "offset";
15 | public static final String SLICE_SIZE = "slice_size";
16 | public static final String LISTPARTS = "listparts";
17 | public static final String SERIAL_UPLOAD = "serial_upload";
18 | public static final String ACCESS_URL = "access_url";
19 | public static final String URL = "url";
20 | public static final String RESOURCE_PATH = "resource_path";
21 | public static final String NAME = "name";
22 | public static final String BIZ_ATTR = "biz_attr";
23 | public static final String FILESIZE = "filesize";
24 | public static final String SHA = "sha";
25 | public static final String CTIME = "ctime";
26 | public static final String MTIME = "mtime";
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/meta/COSObjectInputStream.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.meta;
2 |
3 | import java.io.IOException;
4 | import java.io.InputStream;
5 |
6 | import org.apache.http.client.methods.HttpRequestBase;
7 |
8 | public class COSObjectInputStream extends InputStream {
9 | private InputStream in;
10 | private HttpRequestBase httpRequest;
11 | private boolean eof;
12 |
13 | public COSObjectInputStream(InputStream in, HttpRequestBase httpRequest) {
14 | super();
15 | this.in = in;
16 | this.httpRequest = httpRequest;
17 | }
18 |
19 | private void doAbort() {
20 | if (httpRequest != null) {
21 | httpRequest.abort();
22 | }
23 | closeStream(in);
24 | }
25 |
26 | public int read() throws IOException {
27 | int value = in.read();
28 | if (value == -1) {
29 | eof = true;
30 | }
31 | return value;
32 | }
33 |
34 | public int read(byte[] b) throws IOException {
35 | return read(b, 0, b.length);
36 | }
37 |
38 | public int read(byte[] b, int off, int len) throws IOException {
39 | int value = in.read(b, off, len);
40 | if (value == -1) {
41 | eof = true;
42 | }
43 | return value;
44 | }
45 |
46 | public void reset() throws IOException {
47 | in.reset();
48 | eof = false;
49 | }
50 |
51 | private void closeStream(InputStream in) {
52 | try {
53 | in.close();
54 | } catch (IOException e) {
55 | }
56 | }
57 |
58 |
59 | public void close() throws IOException {
60 | if (eof) {
61 | closeStream(in);
62 | httpRequest.releaseConnection();
63 | } else {
64 | doAbort();
65 | }
66 | }
67 |
68 | public void abort() {
69 | doAbort();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/meta/FileAuthority.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.meta;
2 |
3 | public enum FileAuthority {
4 | INVALID("eInvalid"),
5 | WPRIVATE("eWRPrivate"),
6 | WPRIVATERPUBLIC("eWPrivateRPublic");
7 |
8 | private String authority;
9 |
10 | private FileAuthority(String authority) {
11 | this.authority = authority;
12 | }
13 |
14 | @Override
15 | public String toString() {
16 | return this.authority;
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/meta/FileStat.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.meta;
2 |
3 | import java.io.Serializable;
4 |
5 | import com.qcloud.cos.common_utils.CommonFileUtils;
6 |
7 | /**
8 | * @author chengwu
9 | * 文件状态, 包括文件大小,最近修改时间
10 | */
11 | public class FileStat implements Serializable {
12 |
13 | private static final long serialVersionUID = -4572277446000987482L;
14 |
15 | public FileStat() {}
16 |
17 | public static FileStat getFileStat(String filePath) throws Exception {
18 | FileStat fileStat = new FileStat();
19 | fileStat.fileSize = CommonFileUtils.getFileLength(filePath);
20 | fileStat.lastModifiedTime = CommonFileUtils.getFileLastModified(filePath);
21 | return fileStat;
22 | }
23 |
24 | private long fileSize;
25 | private long lastModifiedTime;
26 |
27 | public long getFileSize() {
28 | return fileSize;
29 | }
30 |
31 | public void setFileSize(long fileSize) {
32 | this.fileSize = fileSize;
33 | }
34 |
35 | public long getLastModifiedTime() {
36 | return lastModifiedTime;
37 | }
38 |
39 | public void setLastModifiedTime(long lastModifiedTime) {
40 | this.lastModifiedTime = lastModifiedTime;
41 | }
42 |
43 | @Override
44 | public boolean equals(Object obj) {
45 | if (this == obj) {
46 | return true;
47 | }
48 |
49 | if (((FileStat) obj).getFileSize() == this.fileSize
50 | && ((FileStat) obj).getLastModifiedTime() == this.lastModifiedTime) {
51 | return true;
52 | } else {
53 | return false;
54 | }
55 | }
56 |
57 | @Override
58 | public int hashCode() {
59 | int hashValue = 1;
60 | final int prime = 31;
61 | hashValue = prime * hashValue + new Long(fileSize).hashCode();
62 | hashValue = prime * hashValue + new Long(lastModifiedTime).hashCode();
63 | return hashValue;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/meta/InsertOnly.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.meta;
2 |
3 | public enum InsertOnly {
4 | OVER_WRITE,
5 | NO_OVER_WRITE
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/meta/OverWrite.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.meta;
2 |
3 | public enum OverWrite {
4 | NO_OVER_WRITE,
5 | OVER_WRITE
6 | }
7 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/meta/SliceFileDataTask.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.meta;
2 |
3 | import java.nio.charset.Charset;
4 | import java.util.concurrent.Callable;
5 |
6 | import org.json.JSONObject;
7 | import org.slf4j.Logger;
8 | import org.slf4j.LoggerFactory;
9 |
10 | import com.qcloud.cos.common_utils.CommonFileUtils;
11 | import com.qcloud.cos.exception.UnknownException;
12 | import com.qcloud.cos.http.AbstractCosHttpClient;
13 | import com.qcloud.cos.http.HttpContentType;
14 | import com.qcloud.cos.http.HttpMethod;
15 | import com.qcloud.cos.http.HttpRequest;
16 | import com.qcloud.cos.http.RequestBodyKey;
17 | import com.qcloud.cos.http.RequestBodyValue;
18 | import com.qcloud.cos.http.RequestHeaderKey;
19 | import com.qcloud.cos.sign.Credentials;
20 | import com.qcloud.cos.sign.Sign;
21 |
22 | /**
23 | * @author chengwu 执行分片上传的任务, 每一个任务由一个线程执行
24 | */
25 | public class SliceFileDataTask implements Callable {
26 |
27 | private static final Logger LOG = LoggerFactory.getLogger(SliceFileDataTask.class);
28 |
29 | private int TaskId;
30 | private int sliceIndex;
31 | private UploadSliceFileContext context;
32 | private AbstractCosHttpClient httpClient;
33 | private Credentials cred;
34 | private String url;
35 | private long signExpired;
36 |
37 | public SliceFileDataTask(int taskId, int sliceIndex, UploadSliceFileContext context,
38 | AbstractCosHttpClient httpClient, Credentials cred, String url, long signExpired) {
39 | super();
40 | TaskId = taskId;
41 | this.sliceIndex = sliceIndex;
42 | this.context = context;
43 | this.httpClient = httpClient;
44 | this.cred = cred;
45 | this.url = url;
46 | this.signExpired = signExpired;
47 | }
48 |
49 | @Override
50 | public JSONObject call() throws Exception {
51 | try {
52 | HttpRequest httpRequest = new HttpRequest();
53 | SlicePart slicePart = context.sliceParts.get(sliceIndex);
54 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.UPLOAD_SLICE_DATA);
55 | if (this.context.isEnableShaDigest()) {
56 | httpRequest.addParam(RequestBodyKey.SHA, context.getEntireFileSha());
57 | }
58 |
59 | httpRequest.addParam(RequestBodyKey.SESSION, context.getSessionId());
60 | httpRequest.addParam(RequestBodyKey.OFFSET, String.valueOf(slicePart.getOffset()));
61 | String sliceContent = "";
62 | if (this.context.isUploadFromBuffer()) {
63 | sliceContent = new String(context.getContentBuffer(),
64 | new Long(slicePart.getOffset()).intValue(), slicePart.getSliceSize(),
65 | Charset.forName("ISO-8859-1"));
66 | } else {
67 | sliceContent = CommonFileUtils.getFileContent(context.getLocalPath(),
68 | slicePart.getOffset(), slicePart.getSliceSize());
69 | }
70 | httpRequest.addParam(RequestBodyKey.FILE_CONTENT, sliceContent);
71 |
72 | long signExpired = System.currentTimeMillis() / 1000 + this.signExpired;
73 | String sign = Sign.getPeriodEffectiveSign(context.getBucketName(), context.getCosPath(),
74 | this.cred, signExpired);
75 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
76 |
77 | httpRequest.setUrl(this.url);
78 | httpRequest.setMethod(HttpMethod.POST);
79 | httpRequest.setContentType(HttpContentType.MULTIPART_FORM_DATA);
80 |
81 | String resultStr = httpClient.sendHttpRequest(httpRequest);
82 | LOG.debug("sliceFileDataTask: " + this.toString() + ", result: " + resultStr);
83 | JSONObject resultJson = new JSONObject(resultStr);
84 | return resultJson;
85 | } catch (Exception e) {
86 | String errMsg = new StringBuilder().append("taskInfo:").append(this.toString())
87 | .append(", Exception:").append(e.toString()).toString();
88 | LOG.error(errMsg);
89 | throw new UnknownException(errMsg);
90 | }
91 | }
92 |
93 | @Override
94 | public String toString() {
95 | StringBuilder sb = new StringBuilder();
96 | sb.append("TaskId:").append(TaskId).append(", SliceIndex:").append(sliceIndex)
97 | .append(", localPath:").append(context.getLocalPath()).append(", uploadUrl:")
98 | .append(this.url);
99 | return sb.toString();
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/meta/SlicePart.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.meta;
2 |
3 | import java.io.Serializable;
4 |
5 | /**
6 | * @author chengwu
7 | * 分片信息,包括偏移量,分片大小,是否上传成功
8 | */
9 | public class SlicePart implements Serializable {
10 |
11 | private static final long serialVersionUID = -7454131654081550885L;
12 |
13 | private long offset;
14 | private int sliceSize;
15 | private boolean uploadCompleted = false;
16 |
17 | public SlicePart() {}
18 |
19 | public long getOffset() {
20 | return offset;
21 | }
22 |
23 | public void setOffset(long offset) {
24 | this.offset = offset;
25 | }
26 |
27 | public int getSliceSize() {
28 | return sliceSize;
29 | }
30 |
31 | public void setSliceSize(int sliceSize) {
32 | this.sliceSize = sliceSize;
33 | }
34 |
35 | public boolean isUploadCompleted() {
36 | return uploadCompleted;
37 | }
38 |
39 | public void setUploadCompleted(boolean uploadCompleted) {
40 | this.uploadCompleted = uploadCompleted;
41 | }
42 |
43 | @Override
44 | public int hashCode() {
45 | int hashValue = 1;
46 | final int prime = 31;
47 | hashValue = prime * hashValue + new Long(offset).hashCode();
48 | hashValue = prime * hashValue + new Integer(sliceSize).hashCode();
49 | hashValue = prime * hashValue + new Boolean(uploadCompleted).hashCode();
50 | return hashValue;
51 | }
52 |
53 | }
54 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/meta/UploadSliceFileContext.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.meta;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashSet;
5 | import java.util.Set;
6 |
7 | import org.json.JSONArray;
8 | import org.json.JSONObject;
9 |
10 | import com.qcloud.cos.common_utils.CommonFileUtils;
11 | import com.qcloud.cos.exception.AbstractCosException;
12 | import com.qcloud.cos.exception.UnknownException;
13 | import com.qcloud.cos.http.ResponseBodyKey;
14 | import com.qcloud.cos.request.UploadSliceFileRequest;
15 |
16 | /**
17 | * 分片上传的上下文信息, 用于在多个步骤之间传递
18 | *
19 | * @author chengwu
20 | *
21 | */
22 | public class UploadSliceFileContext {
23 | // bucket名
24 | private String bucketName = "";
25 | // cos路径
26 | private String cosPath = "";
27 | // 本地文件路径
28 | private String localPath = "";
29 | // 文件bizAttr
30 | private String bizAttr = "";
31 | // 是否覆盖
32 | private InsertOnly insertOnly = InsertOnly.NO_OVER_WRITE;
33 | // 分片大小
34 | private int sliceSize;
35 | // 文件大小
36 | private long fileSize = 0;
37 |
38 | private String url = "";
39 | // 开启sha摘要
40 | private boolean enableShaDigest = true;
41 | // 任务数量
42 | private int taskNum = 1;
43 | // session
44 | private String sessionId = "";
45 | // 全文sha
46 | private String entireFileSha = "";
47 |
48 | private boolean serialUpload = true;
49 |
50 | // 标识是否是从内存中上传文件
51 | private boolean uploadFromBuffer = false;
52 | // 上传的buffer
53 | private byte[] contentBuffer = null;
54 |
55 | // 标识要全部的slice part,包含已经上传和为上传的,已经上传的slice part的完成属性会设置为true
56 | public ArrayList sliceParts;
57 | // 标识已经上传的slice parts
58 | private Set uploadCompletePartsSet;
59 |
60 | public UploadSliceFileContext(UploadSliceFileRequest request) throws AbstractCosException {
61 | this.bucketName = request.getBucketName();
62 | this.cosPath = request.getCosPath();
63 | this.uploadFromBuffer = request.isUploadFromBuffer();
64 | if (request.isUploadFromBuffer()) {
65 | this.contentBuffer = request.getContentBufer();
66 | }
67 | this.localPath = request.getLocalPath();
68 | this.bizAttr = request.getBizAttr();
69 | this.insertOnly = request.getInsertOnly();
70 | this.sliceSize = request.getSliceSize();
71 | this.taskNum = request.getTaskNum();
72 | this.enableShaDigest = request.isEnableShaDigest();
73 | this.sliceParts = new ArrayList();
74 | this.uploadCompletePartsSet = new HashSet();
75 | caculateFileSize();
76 | }
77 |
78 | private void caculateFileSize() throws UnknownException {
79 | try {
80 | if (this.uploadFromBuffer) {
81 | this.fileSize = this.contentBuffer.length;
82 | } else {
83 | this.fileSize = CommonFileUtils.getFileLength(this.localPath);
84 | }
85 | } catch (Exception e) {
86 | throw new UnknownException("caculateFileSize error. " + e.toString());
87 | }
88 | }
89 |
90 | // 切分文件
91 | public ArrayList prepareUploadPartsInfo() {
92 | int sliceCount = new Long((fileSize + (sliceSize - 1)) / sliceSize).intValue();
93 | for (int sliceIndex = 0; sliceIndex < sliceCount; ++sliceIndex) {
94 | SlicePart part = new SlicePart();
95 | long offset = (Long.valueOf(sliceIndex).longValue()) * sliceSize;
96 | part.setOffset(offset);
97 | if (sliceIndex != sliceCount - 1) {
98 | part.setSliceSize(sliceSize);
99 | } else {
100 | part.setSliceSize(new Long(fileSize - offset).intValue());
101 | }
102 | part.setUploadCompleted(uploadCompletePartsSet.contains(offset));
103 | sliceParts.add(part);
104 | }
105 | return sliceParts;
106 | }
107 |
108 |
109 | public void setUploadCompleteParts(JSONArray listPartsArry) {
110 | int listPartsLen = listPartsArry.length();
111 | for (int listPartsIndex = 0; listPartsIndex < listPartsLen; ++listPartsIndex) {
112 | JSONObject listPartMember = listPartsArry.getJSONObject(listPartsIndex);
113 | long partOffset = listPartMember.getLong(ResponseBodyKey.Data.OFFSET);
114 | this.uploadCompletePartsSet.add(partOffset);
115 | }
116 | }
117 |
118 |
119 | public String getBucketName() {
120 | return bucketName;
121 | }
122 |
123 | public void setBucketName(String bucketName) {
124 | this.bucketName = bucketName;
125 | }
126 |
127 | public String getCosPath() {
128 | return cosPath;
129 | }
130 |
131 | public void setCosPath(String cosPath) {
132 | this.cosPath = cosPath;
133 | }
134 |
135 | public String getLocalPath() {
136 | return localPath;
137 | }
138 |
139 | public void setLocalPath(String localPath) {
140 | this.localPath = localPath;
141 | }
142 |
143 | public String getBizAttr() {
144 | return bizAttr;
145 | }
146 |
147 | public void setBizAttr(String bizAttr) {
148 | this.bizAttr = bizAttr;
149 | }
150 |
151 | public InsertOnly getInsertOnly() {
152 | return insertOnly;
153 | }
154 |
155 | public void setInsertOnly(InsertOnly insertOnly) {
156 | this.insertOnly = insertOnly;
157 | }
158 |
159 | public int getSliceSize() {
160 | return sliceSize;
161 | }
162 |
163 | public void setSliceSize(int sliceSize) {
164 | this.sliceSize = sliceSize;
165 | }
166 |
167 | public long getFileSize() {
168 | return fileSize;
169 | }
170 |
171 | public void setFileSize(long fileSize) {
172 | this.fileSize = fileSize;
173 | }
174 |
175 | public String getUrl() {
176 | return url;
177 | }
178 |
179 | public void setUrl(String url) {
180 | this.url = url;
181 | }
182 |
183 | public boolean isEnableShaDigest() {
184 | return enableShaDigest;
185 | }
186 |
187 | public void setEnableShaDigest(boolean enableShaDigest) {
188 | this.enableShaDigest = enableShaDigest;
189 | }
190 |
191 | public int getTaskNum() {
192 | return taskNum;
193 | }
194 |
195 | public void setTaskNum(int taskNum) {
196 | this.taskNum = taskNum;
197 | }
198 |
199 | public String getSessionId() {
200 | return sessionId;
201 | }
202 |
203 | public void setSessionId(String sessionId) {
204 | this.sessionId = sessionId;
205 | }
206 |
207 | public String getEntireFileSha() {
208 | return entireFileSha;
209 | }
210 |
211 | public void setEntireFileSha(String entireFileSha) {
212 | this.entireFileSha = entireFileSha;
213 | }
214 |
215 | public boolean isSerialUpload() {
216 | return serialUpload;
217 | }
218 |
219 | public void setSerialUpload(boolean serialUpload) {
220 | this.serialUpload = serialUpload;
221 | }
222 |
223 | public boolean isUploadFromBuffer() {
224 | return uploadFromBuffer;
225 | }
226 |
227 | public void setUploadFromBuffer(boolean uploadFromBuffer) {
228 | this.uploadFromBuffer = uploadFromBuffer;
229 | }
230 |
231 | public byte[] getContentBuffer() {
232 | return contentBuffer;
233 | }
234 |
235 | public void setContentBuffer(byte[] contentBuffer) {
236 | this.contentBuffer = contentBuffer;
237 | }
238 |
239 | }
240 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/op/BaseOp.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.op;
2 |
3 | import com.qcloud.cos.ClientConfig;
4 | import com.qcloud.cos.common_utils.CommonPathUtils;
5 | import com.qcloud.cos.exception.AbstractCosException;
6 | import com.qcloud.cos.http.AbstractCosHttpClient;
7 | import com.qcloud.cos.http.HttpContentType;
8 | import com.qcloud.cos.http.HttpMethod;
9 | import com.qcloud.cos.http.HttpRequest;
10 | import com.qcloud.cos.http.RequestBodyKey;
11 | import com.qcloud.cos.http.RequestBodyValue;
12 | import com.qcloud.cos.http.RequestHeaderKey;
13 | import com.qcloud.cos.http.RequestHeaderValue;
14 | import com.qcloud.cos.request.AbstractBaseRequest;
15 | import com.qcloud.cos.request.AbstractDelRequest;
16 | import com.qcloud.cos.request.AbstractStatRequest;
17 | import com.qcloud.cos.sign.Credentials;
18 | import com.qcloud.cos.sign.Sign;
19 |
20 | /**
21 | * @author chengwu 封装目录和文件共同的操作
22 | */
23 | public abstract class BaseOp {
24 | // 配置信息
25 | protected ClientConfig config;
26 | // 鉴权信息
27 | protected Credentials cred;
28 | // http请求发送对象
29 | protected AbstractCosHttpClient httpClient;
30 |
31 | public BaseOp(ClientConfig config, Credentials cred, AbstractCosHttpClient httpClient) {
32 | super();
33 | this.config = config;
34 | this.cred = cred;
35 | this.httpClient = httpClient;
36 | }
37 |
38 | public void setConfig(ClientConfig config) {
39 | this.config = config;
40 | }
41 |
42 | public void setCred(Credentials cred) {
43 | this.cred = cred;
44 | }
45 |
46 | public void setHttpClient(AbstractCosHttpClient httpClient) {
47 | this.httpClient = httpClient;
48 | }
49 |
50 | /**
51 | * 根据APPID, BUCKET, COS_PATH生成经过URL编码的URL
52 | *
53 | * @param request 基本类型的请求
54 | * @return URL字符串
55 | * @throws AbstractCosException
56 | */
57 | protected String buildUrl(AbstractBaseRequest request) throws AbstractCosException {
58 | String endPoint = new StringBuilder().append(this.config.getUploadCosEndPointPrefix())
59 | .append(this.config.getUploadCosEndPointDomain())
60 | .append(this.config.getUploadCosEndPointSuffix()).toString();
61 | long appId = this.cred.getAppId();
62 | String bucketName = request.getBucketName();
63 | String cosPath = request.getCosPath();
64 | cosPath = CommonPathUtils.encodeRemotePath(cosPath);
65 | return String.format("%s/%d/%s%s", endPoint, appId, bucketName, cosPath);
66 | }
67 |
68 | /**
69 | * 删除文件或者目录
70 | *
71 | * @param request 删除文件或者目录的请求, 类型为DelFileRequest或者DelFolderRequest
72 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
73 | * message为success或者失败原因
74 | * @throws AbstractCosException SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
75 | */
76 | protected String delBase(final AbstractDelRequest request) throws AbstractCosException {
77 | request.check_param();
78 |
79 | String url = buildUrl(request);
80 | String sign =
81 | Sign.getOneEffectiveSign(request.getBucketName(), request.getCosPath(), this.cred);
82 |
83 | HttpRequest httpRequest = new HttpRequest();
84 | httpRequest.setUrl(url);
85 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
86 | httpRequest.addHeader(RequestHeaderKey.Content_TYPE, RequestHeaderValue.ContentType.JSON);
87 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
88 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.DELETE);
89 | httpRequest.setMethod(HttpMethod.POST);
90 | httpRequest.setContentType(HttpContentType.APPLICATION_JSON);
91 | return httpClient.sendHttpRequest(httpRequest);
92 | }
93 |
94 | /**
95 | * 获取文件或者目录的属性
96 | *
97 | * @param request 文件或者目录的属性请求, 类型为StatFileRequest或者StatFolderRequest
98 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
99 | * message为success或者失败原因
100 | * @throws AbstractCosException SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
101 | */
102 | protected String statBase(final AbstractStatRequest request) throws AbstractCosException {
103 | request.check_param();
104 |
105 | String url = buildUrl(request);
106 | long signExpired = System.currentTimeMillis() / 1000 + this.config.getSignExpired();
107 | String sign = Sign.getPeriodEffectiveSign(request.getBucketName(), request.getCosPath(),
108 | this.cred, signExpired);
109 |
110 | HttpRequest httpRequest = new HttpRequest();
111 | httpRequest.setUrl(url);
112 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
113 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
114 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.STAT);
115 | httpRequest.setMethod(HttpMethod.GET);
116 |
117 | return httpClient.sendHttpRequest(httpRequest);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/op/FileOp.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.op;
2 |
3 | import java.io.BufferedInputStream;
4 | import java.io.BufferedOutputStream;
5 | import java.io.File;
6 | import java.io.FileNotFoundException;
7 | import java.io.FileOutputStream;
8 | import java.io.IOException;
9 | import java.io.InputStream;
10 | import java.io.OutputStream;
11 | import java.nio.charset.Charset;
12 | import java.util.ArrayList;
13 | import java.util.List;
14 | import java.util.concurrent.ExecutorService;
15 | import java.util.concurrent.Executors;
16 | import java.util.concurrent.Future;
17 | import java.util.concurrent.TimeUnit;
18 |
19 | import org.json.JSONArray;
20 | import org.json.JSONObject;
21 | import org.slf4j.Logger;
22 | import org.slf4j.LoggerFactory;
23 |
24 | import com.qcloud.cos.ClientConfig;
25 | import com.qcloud.cos.common_utils.CommonCodecUtils;
26 | import com.qcloud.cos.common_utils.CommonFileUtils;
27 | import com.qcloud.cos.common_utils.CommonPathUtils;
28 | import com.qcloud.cos.exception.AbstractCosException;
29 | import com.qcloud.cos.exception.ParamException;
30 | import com.qcloud.cos.exception.UnknownException;
31 | import com.qcloud.cos.http.AbstractCosHttpClient;
32 | import com.qcloud.cos.http.HttpContentType;
33 | import com.qcloud.cos.http.HttpMethod;
34 | import com.qcloud.cos.http.HttpRequest;
35 | import com.qcloud.cos.http.RequestBodyKey;
36 | import com.qcloud.cos.http.RequestBodyValue;
37 | import com.qcloud.cos.http.RequestHeaderKey;
38 | import com.qcloud.cos.http.RequestHeaderValue;
39 | import com.qcloud.cos.http.ResponseBodyKey;
40 | import com.qcloud.cos.meta.InsertOnly;
41 | import com.qcloud.cos.meta.SliceFileDataTask;
42 | import com.qcloud.cos.meta.UploadSliceFileContext;
43 | import com.qcloud.cos.request.DelFileRequest;
44 | import com.qcloud.cos.request.GetFileInputStreamRequest;
45 | import com.qcloud.cos.request.GetFileLocalRequest;
46 | import com.qcloud.cos.request.ListPartsRequest;
47 | import com.qcloud.cos.request.MoveFileRequest;
48 | import com.qcloud.cos.request.StatFileRequest;
49 | import com.qcloud.cos.request.UpdateFileRequest;
50 | import com.qcloud.cos.request.UploadFileRequest;
51 | import com.qcloud.cos.request.UploadSliceFileRequest;
52 | import com.qcloud.cos.sign.Credentials;
53 | import com.qcloud.cos.sign.Sign;
54 |
55 | /**
56 | * @author chengwu 此类封装了文件操作
57 | */
58 | public class FileOp extends BaseOp {
59 |
60 | private static final Logger LOG = LoggerFactory.getLogger(FileOp.class);
61 |
62 | public FileOp(ClientConfig config, Credentials cred, AbstractCosHttpClient client) {
63 | super(config, cred, client);
64 | }
65 |
66 | private String buildGetFileUrl(GetFileInputStreamRequest request) throws AbstractCosException {
67 | StringBuilder strBuilder = new StringBuilder();
68 | strBuilder.append(this.config.getDownCosEndPointPrefix()).append(request.getBucketName())
69 | .append("-").append(this.cred.getAppId()).append(".");
70 | if (request.isUseCDN()) {
71 | strBuilder.append("file.myqcloud.com");
72 | } else {
73 | strBuilder.append(this.config.getDownCosEndPointDomain());
74 | }
75 | strBuilder.append(CommonPathUtils.encodeRemotePath(request.getCosPath()));
76 | String url = strBuilder.toString();
77 | return url;
78 | }
79 |
80 | /**
81 | * 更新文件属性请求
82 | *
83 | * @param request 更新文件属性请求
84 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
85 | * message为success或者失败原因
86 | * @throws AbstractCosException SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
87 | */
88 | public String updateFile(final UpdateFileRequest request) throws AbstractCosException {
89 | request.check_param();
90 |
91 | String url = buildUrl(request);
92 | String sign =
93 | Sign.getOneEffectiveSign(request.getBucketName(), request.getCosPath(), this.cred);
94 |
95 | HttpRequest httpRequest = new HttpRequest();
96 | httpRequest.setUrl(url);
97 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
98 | httpRequest.addHeader(RequestHeaderKey.Content_TYPE, RequestHeaderValue.ContentType.JSON);
99 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
100 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.UPDATE);
101 | int updateFlag = request.getUpdateFlag();
102 | if ((updateFlag & 0x01) != 0) {
103 | httpRequest.addParam(RequestBodyKey.BIZ_ATTR, request.getBizAttr());
104 | }
105 | if ((updateFlag & 0x40) != 0) {
106 | String customHeaderStr = new JSONObject(request.getCustomHeaders()).toString();
107 | httpRequest.addParam(RequestBodyKey.CUSTOM_HEADERS, customHeaderStr);
108 | }
109 | if ((updateFlag & 0x80) != 0) {
110 | httpRequest.addParam(RequestBodyKey.AUTHORITY, request.getAuthority().toString());
111 | }
112 | httpRequest.setMethod(HttpMethod.POST);
113 | httpRequest.setContentType(HttpContentType.APPLICATION_JSON);
114 | return httpClient.sendHttpRequest(httpRequest);
115 | }
116 |
117 | /**
118 | * 删除文件请求
119 | *
120 | * @param request 删除文件请求
121 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
122 | * message为success或者失败原因
123 | * @throws AbstractCosException SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
124 | */
125 | public String delFile(DelFileRequest request) throws AbstractCosException {
126 | return super.delBase(request);
127 | }
128 |
129 | /**
130 | * 获取文件属性请求
131 | *
132 | * @param request 获取文件属性请求
133 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
134 | * message为success或者失败原因
135 | * @throws AbstractCosException SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
136 | */
137 | public String statFile(StatFileRequest request) throws AbstractCosException {
138 | return super.statBase(request);
139 | }
140 |
141 | /**
142 | * 上传文件请求, 对小文件(8MB以下使用单文件上传接口), 大文件使用分片上传接口
143 | *
144 | * @param request 上传文件请求
145 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
146 | * message为success或者失败原因
147 | * @throws AbstractCosException SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
148 | */
149 | public String uploadFile(UploadFileRequest request) throws AbstractCosException {
150 | request.check_param();
151 |
152 | String localPath = request.getLocalPath();
153 | long fileSize = 0;
154 | if (request.isUploadFromBuffer()) {
155 | fileSize = request.getContentBufer().length;
156 | } else {
157 | try {
158 | fileSize = CommonFileUtils.getFileLength(localPath);
159 | } catch (Exception e) {
160 | throw new UnknownException(e.toString());
161 | }
162 | }
163 |
164 | long suitSingleFileSize = 8 * 1024 * 1024;
165 | if (fileSize < suitSingleFileSize) {
166 | return uploadSingleFile(request);
167 | } else {
168 | UploadSliceFileRequest sliceRequest = new UploadSliceFileRequest(request);
169 | sliceRequest.setInsertOnly(request.getInsertOnly());
170 | if (request.isUploadFromBuffer()) {
171 | sliceRequest.setContentBufer(request.getContentBufer());
172 | }
173 | sliceRequest.setEnableShaDigest(request.isEnableShaDigest());
174 | sliceRequest.setTaskNum(request.getTaskNum());
175 | return uploadSliceFile(sliceRequest);
176 | }
177 | }
178 |
179 | /**
180 | * 上传单文件请求, 不分片
181 | *
182 | * @param request 上传文件请求
183 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
184 | * message为success或者失败原因
185 | * @throws AbstractCosException SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
186 | */
187 | public String uploadSingleFile(UploadFileRequest request) throws AbstractCosException {
188 | request.check_param();
189 |
190 | String localPath = request.getLocalPath();
191 | long fileSize = 0;
192 | if (request.isUploadFromBuffer()) {
193 | fileSize = request.getContentBufer().length;
194 | } else {
195 | try {
196 | fileSize = CommonFileUtils.getFileLength(localPath);
197 | } catch (Exception e) {
198 | throw new UnknownException(e.toString());
199 | }
200 | }
201 | // 单文件上传上限不超过20MB
202 | if (fileSize > 20 * 1024 * 1024) {
203 | throw new ParamException("file is to big, please use uploadFile interface!");
204 | }
205 |
206 | String fileContent = "";
207 | String shaDigest = "";
208 | try {
209 | if (request.isUploadFromBuffer()) {
210 | fileContent = new String(request.getContentBufer(), Charset.forName("ISO-8859-1"));
211 | shaDigest = CommonCodecUtils.getBufferSha1(request.getContentBufer());
212 | } else {
213 | fileContent = CommonFileUtils.getFileContent(localPath);
214 | shaDigest = CommonCodecUtils.getEntireFileSha1(localPath);
215 | }
216 | } catch (Exception e) {
217 | throw new UnknownException(e.toString());
218 | }
219 |
220 | String url = buildUrl(request);
221 | long signExpired = System.currentTimeMillis() / 1000 + this.config.getSignExpired();
222 | String sign = Sign.getPeriodEffectiveSign(request.getBucketName(), request.getCosPath(),
223 | this.cred, signExpired);
224 |
225 | HttpRequest httpRequest = new HttpRequest();
226 | httpRequest.setUrl(url);
227 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
228 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
229 |
230 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.UPLOAD);
231 | httpRequest.addParam(RequestBodyKey.SHA, shaDigest);
232 | httpRequest.addParam(RequestBodyKey.BIZ_ATTR, request.getBizAttr());
233 | httpRequest.addParam(RequestBodyKey.FILE_CONTENT, fileContent);
234 | httpRequest.addParam(RequestBodyKey.INSERT_ONLY,
235 | String.valueOf(request.getInsertOnly().ordinal()));
236 |
237 | httpRequest.setMethod(HttpMethod.POST);
238 | httpRequest.setContentType(HttpContentType.MULTIPART_FORM_DATA);
239 |
240 | String retStr = httpClient.sendHttpRequest(httpRequest);
241 | if (request.getInsertOnly() != InsertOnly.OVER_WRITE) {
242 | return retStr;
243 | }
244 | // 对于Overwrite类型,覆盖上传失败,做特殊处理,删掉重新传
245 | JSONObject retJson = new JSONObject(retStr);
246 | if (retJson.getInt("code") == 0) {
247 | return retStr;
248 | }
249 | // 1. Delete
250 | DelFileRequest del_request =
251 | new DelFileRequest(request.getBucketName(), request.getCosPath());
252 | String delRet = delFile(del_request);
253 | JSONObject delJson = new JSONObject(delRet);
254 | if (delJson.getInt("code") != 0) {
255 | return retStr;
256 | }
257 | // 2. Upload Again
258 | return httpClient.sendHttpRequest(httpRequest);
259 | }
260 |
261 | /**
262 | * 分片上传文件
263 | *
264 | * @param request 分片上传请求
265 | * @return 服务器端返回的操作结果,成员code为0表示成功,具体参照文档手册
266 | * @throws Exception
267 | */
268 | public String uploadSliceFile(UploadSliceFileRequest request) throws AbstractCosException {
269 | request.check_param();
270 | UploadSliceFileContext context = new UploadSliceFileContext(request);
271 | context.setUrl(buildUrl(request));
272 | String retStr = uploadFileWithCheckPoint(context);
273 |
274 | if (request.getInsertOnly() != InsertOnly.OVER_WRITE) {
275 | return retStr;
276 | }
277 | // 对于Overwrite类型,覆盖上传失败,做特殊处理,删掉重新传
278 | JSONObject retJson = new JSONObject(retStr);
279 | if (retJson.getInt("code") == 0) {
280 | return retStr;
281 | }
282 | // 1. Delete
283 | DelFileRequest del_request =
284 | new DelFileRequest(request.getBucketName(), request.getCosPath());
285 | String delRet = delFile(del_request);
286 | JSONObject delJson = new JSONObject(delRet);
287 | if (delJson.getInt("code") != 0) {
288 | return retStr;
289 | }
290 | // 2. Upload Again
291 | retStr = uploadFileWithCheckPoint(context);
292 | retJson = new JSONObject(retStr);
293 | if (retJson.getInt("code") != 0) {
294 | del_request = new DelFileRequest(request.getBucketName(), request.getCosPath());
295 | delFile(del_request);
296 | }
297 | return retStr;
298 | }
299 |
300 | /**
301 | * 移动文件请求(重命名)
302 | *
303 | * @param request 移动文件请求
304 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功, 其他为失败,
305 | * message为success或者失败原因
306 | * @throws AbstractCosException SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
307 | */
308 | public String moveFile(MoveFileRequest request) throws AbstractCosException {
309 | request.check_param();
310 |
311 | String url = buildUrl(request);
312 | String sign =
313 | Sign.getOneEffectiveSign(request.getBucketName(), request.getCosPath(), this.cred);
314 |
315 | HttpRequest httpRequest = new HttpRequest();
316 | httpRequest.setUrl(url);
317 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
318 | httpRequest.addHeader(RequestHeaderKey.Content_TYPE, RequestHeaderValue.ContentType.JSON);
319 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
320 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.MOVE);
321 | httpRequest.addParam(RequestBodyKey.DEST_FIELD, request.getDstCosPath());
322 | httpRequest.addParam(RequestBodyKey.TO_OVER_WRITE,
323 | String.valueOf(request.getOverWrite().ordinal()));
324 | httpRequest.setMethod(HttpMethod.POST);
325 | httpRequest.setContentType(HttpContentType.APPLICATION_JSON);
326 | return httpClient.sendHttpRequest(httpRequest);
327 | }
328 |
329 | // 断点续传
330 | private String uploadFileWithCheckPoint(UploadSliceFileContext context)
331 | throws AbstractCosException {
332 | JSONObject initResult = sendSliceInit(context);
333 |
334 | int initResultCode = initResult.getInt(ResponseBodyKey.CODE);
335 | // 4019文件未上传完成,这时候应该用断点续传
336 | if (initResultCode != 0 && initResultCode != -4019) {
337 | return initResult.toString();
338 | }
339 |
340 | if (initResultCode == 0) {
341 | JSONObject data = initResult.getJSONObject(ResponseBodyKey.DATA);
342 | if (data.has(ResponseBodyKey.Data.ACCESS_URL)) {
343 | return initResult.toString();
344 | }
345 | if (data.has(ResponseBodyKey.Data.SERIAL_UPLOAD)
346 | && data.getInt(ResponseBodyKey.Data.SERIAL_UPLOAD) == 1) {
347 | LOG.debug("SERIAL_UPLOAD is true");
348 | context.setSerialUpload(true);
349 | } else {
350 | LOG.debug("SERIAL_UPLOAD is false");;
351 | context.setSerialUpload(false);
352 | }
353 | context.setSessionId(data.getString(ResponseBodyKey.Data.SESSION));
354 | // 如果服务端返回的slice_slize和用户要求的不一致, 则重新分片
355 | if (data.getInt(ResponseBodyKey.Data.SLICE_SIZE) != context.getSliceSize()) {
356 | context.setSliceSize(data.getInt(ResponseBodyKey.Data.SLICE_SIZE));
357 | }
358 | } else {
359 | ListPartsRequest listPartsRequest =
360 | new ListPartsRequest(context.getBucketName(), context.getCosPath());
361 | String listPartsResult = sliceListParts(listPartsRequest);
362 | JSONObject listPartsJson = new JSONObject(listPartsResult);
363 | if (listPartsJson.getInt(ResponseBodyKey.CODE) != 0) {
364 | return listPartsJson.toString();
365 | }
366 |
367 | JSONObject data = listPartsJson.getJSONObject(ResponseBodyKey.DATA);
368 | if (data.has(ResponseBodyKey.Data.LISTPARTS)) {
369 | JSONArray listPartsJsonArry = data.getJSONArray(ResponseBodyKey.Data.LISTPARTS);
370 | context.setUploadCompleteParts(listPartsJsonArry);
371 | }
372 | context.setSessionId(data.getString(ResponseBodyKey.Data.SESSION));
373 | }
374 |
375 | context.prepareUploadPartsInfo();
376 | // 并行发送数据分片
377 | JSONObject sendParallelRet = sendSliceDataParallel(context);
378 | if (sendParallelRet.getInt(ResponseBodyKey.CODE) != 0) {
379 | return sendParallelRet.toString();
380 | }
381 |
382 | // 发送finish分片
383 | JSONObject finishRet = sendSliceFinish(context);
384 | return finishRet.toString();
385 | }
386 |
387 | /**
388 | * 分片上传第一步,发送init分片
389 | *
390 | * @param context 分片上传请求上下文
391 | * @return 服务器端返回的操作结果,code为0表示成功,其他包括sessionId、offset等,具体参见文档手册
392 | * @throws Exception
393 | */
394 | private JSONObject sendSliceInit(UploadSliceFileContext context) throws AbstractCosException {
395 | String localPath = context.getLocalPath();
396 | long fileSize = context.getFileSize();
397 | int sliceSize = context.getSliceSize();
398 |
399 | StringBuilder entireDigestSb = new StringBuilder();
400 | String slicePartDigest = "";
401 | try {
402 | if (context.isEnableShaDigest()) {
403 | if (context.isUploadFromBuffer()) {
404 | slicePartDigest = CommonCodecUtils.getSlicePartSha1(context.getContentBuffer(),
405 | sliceSize, entireDigestSb);
406 | } else {
407 | slicePartDigest =
408 | CommonCodecUtils.getSlicePartSha1(localPath, sliceSize, entireDigestSb);
409 | }
410 | context.setEntireFileSha(entireDigestSb.toString());
411 | LOG.debug("slicePartDigest: " + slicePartDigest);
412 | }
413 | } catch (Exception e) {
414 | throw new UnknownException(e.getMessage());
415 | }
416 |
417 | String url = context.getUrl();
418 | long signExpired = System.currentTimeMillis() / 1000 + this.config.getSignExpired();
419 | String sign = Sign.getPeriodEffectiveSign(context.getBucketName(), context.getCosPath(),
420 | this.cred, signExpired);
421 |
422 | HttpRequest httpRequest = new HttpRequest();
423 | httpRequest.setUrl(url);
424 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
425 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
426 | httpRequest.addParam(RequestBodyKey.FILE_SIZE, String.valueOf(fileSize));
427 | httpRequest.addParam(RequestBodyKey.SLICE_SIZE, String.valueOf(sliceSize));
428 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.UPLOAD_SLICE_INIT);
429 | httpRequest.addParam(RequestBodyKey.INSERT_ONLY,
430 | String.valueOf(context.getInsertOnly().ordinal()));
431 | httpRequest.addParam(RequestBodyKey.BIZ_ATTR, context.getBizAttr());
432 | if (context.isEnableShaDigest()) {
433 | httpRequest.addParam(RequestBodyKey.SHA, entireDigestSb.toString());
434 | httpRequest.addParam(RequestBodyKey.UPLOAD_PARTS, slicePartDigest);
435 | }
436 |
437 | httpRequest.setMethod(HttpMethod.POST);
438 | httpRequest.setContentType(HttpContentType.MULTIPART_FORM_DATA);
439 |
440 | JSONObject resultJson = null;
441 | String resultStr = this.httpClient.sendHttpRequest(httpRequest);
442 | LOG.debug("sendSliceInit, resultStr: " + resultStr);
443 | resultJson = new JSONObject(resultStr);
444 | return resultJson;
445 | }
446 |
447 | /**
448 | * 分片上传第二步,发送数据分片
449 | *
450 | * @param context 分片上传请求
451 | * @return 服务器端返回的操作结果,code为0表示成功
452 | * @throws Exception
453 | */
454 | private JSONObject sendSliceDataParallel(UploadSliceFileContext context)
455 | throws AbstractCosException {
456 | List> allSliceTasks = new ArrayList>();
457 | // 默认串行执行,只用一个线程,如果server端支持并行上传,则用多个线程执行
458 | int threadNum = 1;
459 | if (!context.isSerialUpload()) {
460 | threadNum = context.getTaskNum();
461 | }
462 | ExecutorService service = Executors.newFixedThreadPool(threadNum);
463 |
464 | String url = context.getUrl();
465 | long signExpired = this.config.getSignExpired();
466 | for (int sliceIndex = 0; sliceIndex < context.sliceParts.size(); ++sliceIndex) {
467 | if (!context.sliceParts.get(sliceIndex).isUploadCompleted()) {
468 | SliceFileDataTask dataTask = new SliceFileDataTask(sliceIndex, sliceIndex, context,
469 | httpClient, cred, url, signExpired);
470 | allSliceTasks.add(service.submit(dataTask));
471 | }
472 | }
473 | service.shutdown();
474 |
475 | try {
476 | service.awaitTermination(Long.MAX_VALUE, TimeUnit.SECONDS);
477 | service.shutdownNow();
478 | } catch (Exception e) {
479 | throw new UnknownException(e.getMessage());
480 | }
481 |
482 | JSONObject taskResult = null;
483 | if (allSliceTasks.size() == 0) {
484 | taskResult = new JSONObject();
485 | taskResult.put(ResponseBodyKey.CODE, 0);
486 | return taskResult;
487 | }
488 |
489 | for (Future task : allSliceTasks) {
490 | try {
491 | taskResult = task.get();
492 | } catch (Exception e) {
493 | throw new UnknownException(e.getMessage());
494 | }
495 | if (taskResult.getInt(ResponseBodyKey.CODE) != 0) {
496 | return taskResult;
497 | }
498 | }
499 |
500 | return taskResult;
501 | }
502 |
503 | /**
504 | * 最后一步, 发送finish分片
505 | *
506 | * @return 服务器端返回的操作结果,成功code为0
507 | * @throws Exception
508 | */
509 | private JSONObject sendSliceFinish(UploadSliceFileContext context) throws AbstractCosException {
510 | String url = context.getUrl();
511 |
512 | long signExpired = System.currentTimeMillis() / 1000 + this.config.getSignExpired();
513 | String sign = Sign.getPeriodEffectiveSign(context.getBucketName(), context.getCosPath(),
514 | this.cred, signExpired);
515 |
516 | HttpRequest httpRequest = new HttpRequest();
517 | httpRequest.setUrl(url);
518 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
519 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
520 | httpRequest.addParam(RequestBodyKey.SESSION, context.getSessionId());
521 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.UPLOAD_SLICE_FINISH);
522 | if (context.isEnableShaDigest()) {
523 | httpRequest.addParam(RequestBodyKey.SHA, context.getEntireFileSha());
524 | }
525 | httpRequest.addParam(RequestBodyKey.FILE_SIZE, String.valueOf(context.getFileSize()));
526 |
527 | httpRequest.setContentType(HttpContentType.MULTIPART_FORM_DATA);
528 | httpRequest.setMethod(HttpMethod.POST);
529 |
530 | JSONObject resultJson = null;
531 | String resultStr = this.httpClient.sendHttpRequest(httpRequest);
532 | resultJson = new JSONObject(resultStr);
533 | LOG.debug("sendSliceFinish, resultStr: " + resultStr);
534 | return resultJson;
535 | }
536 |
537 | public String sliceListParts(ListPartsRequest request) throws AbstractCosException {
538 | request.check_param();
539 |
540 | String url = buildUrl(request);
541 | long signExpired = System.currentTimeMillis() / 1000 + this.config.getSignExpired();
542 | String sign = Sign.getPeriodEffectiveSign(request.getBucketName(), request.getCosPath(),
543 | this.cred, signExpired);
544 |
545 | HttpRequest httpRequest = new HttpRequest();
546 | httpRequest.setUrl(url);
547 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
548 | httpRequest.addHeader(RequestHeaderKey.Content_TYPE, RequestHeaderValue.ContentType.JSON);
549 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
550 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.UPLOAD_SLICE_LIST);
551 | httpRequest.setMethod(HttpMethod.POST);
552 | httpRequest.setContentType(HttpContentType.APPLICATION_JSON);
553 | return httpClient.sendHttpRequest(httpRequest);
554 | }
555 |
556 | public String getFileLocal(GetFileLocalRequest request) throws AbstractCosException {
557 | InputStream in = getFileInputStream(request);
558 | BufferedInputStream bis = new BufferedInputStream(in);
559 | OutputStream out = null;
560 | try {
561 | out = new FileOutputStream(new File(request.getLocalPath()));
562 | } catch (FileNotFoundException e) {
563 | throw new UnknownException(e.getMessage());
564 | }
565 | BufferedOutputStream bos = new BufferedOutputStream(out);
566 | int inByte;
567 | try {
568 | while ((inByte = bis.read()) != -1)
569 | bos.write(inByte);
570 | } catch (IOException e) {
571 | throw new UnknownException(e.getMessage());
572 | } finally {
573 | try {
574 | bis.close();
575 | bos.close();
576 | } catch (IOException e) {
577 | throw new UnknownException(e.getMessage());
578 | }
579 | }
580 | JSONObject retJson = new JSONObject();
581 | retJson.put(ResponseBodyKey.CODE, 0);
582 | retJson.put(ResponseBodyKey.MESSAGE, "SUCCESS");
583 | return retJson.toString();
584 | }
585 |
586 | public InputStream getFileInputStream(GetFileInputStreamRequest request)
587 | throws AbstractCosException {
588 | String url = buildGetFileUrl(request);
589 | long signExpired = System.currentTimeMillis() / 1000 + this.config.getSignExpired();
590 | String sign = Sign.getDownLoadSign(request.getBucketName(), request.getCosPath(), this.cred,
591 | signExpired);
592 |
593 | StringBuilder rangeBuilder = new StringBuilder();
594 | if (request.getRangeStart() != 0 || request.getRangeEnd() != Long.MAX_VALUE) {
595 | rangeBuilder.append("bytes=").append(request.getRangeStart()).append("-");
596 | rangeBuilder.append(request.getRangeEnd());
597 | }
598 |
599 | HttpRequest httpRequest = new HttpRequest();
600 | httpRequest.setUrl(url);
601 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
602 | if (!rangeBuilder.toString().isEmpty()) {
603 | httpRequest.addHeader(RequestHeaderKey.RANGE, rangeBuilder.toString());
604 | }
605 | if (!request.getReferer().isEmpty()) {
606 | httpRequest.addHeader(RequestHeaderKey.REFERER, request.getReferer());
607 | }
608 | httpRequest.addParam(RequestHeaderKey.SIGN, sign);
609 | httpRequest.setMethod(HttpMethod.GET);
610 | return httpClient.getFileInputStream(httpRequest);
611 | }
612 | }
613 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/op/FolderOp.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.op;
2 |
3 | import com.qcloud.cos.ClientConfig;
4 | import com.qcloud.cos.exception.AbstractCosException;
5 | import com.qcloud.cos.http.AbstractCosHttpClient;
6 | import com.qcloud.cos.http.HttpContentType;
7 | import com.qcloud.cos.http.HttpMethod;
8 | import com.qcloud.cos.http.HttpRequest;
9 | import com.qcloud.cos.http.RequestBodyKey;
10 | import com.qcloud.cos.http.RequestBodyValue;
11 | import com.qcloud.cos.http.RequestHeaderKey;
12 | import com.qcloud.cos.http.RequestHeaderValue;
13 | import com.qcloud.cos.request.CreateFolderRequest;
14 | import com.qcloud.cos.request.DelFolderRequest;
15 | import com.qcloud.cos.request.ListFolderRequest;
16 | import com.qcloud.cos.request.StatFolderRequest;
17 | import com.qcloud.cos.request.UpdateFolderRequest;
18 | import com.qcloud.cos.sign.Credentials;
19 | import com.qcloud.cos.sign.Sign;
20 |
21 | /**
22 | * @author chengwu
23 | * 此类封装了常用的目录操作
24 | */
25 | public class FolderOp extends BaseOp {
26 |
27 | public FolderOp(ClientConfig config, Credentials cred, AbstractCosHttpClient client) {
28 | super(config, cred, client);
29 | }
30 |
31 | /**
32 | * 更新目录属性请求
33 | *
34 | * @param request
35 | * 更新目录属性请求
36 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功,
37 | * 其他为失败, message为success或者失败原因
38 | * @throws AbstractCosException
39 | * SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
40 | */
41 | public String updateFolder(UpdateFolderRequest request) throws AbstractCosException {
42 | request.check_param();
43 |
44 | String url = buildUrl(request);
45 | String sign = Sign.getOneEffectiveSign(request.getBucketName(), request.getCosPath(), this.cred);
46 |
47 | HttpRequest httpRequest = new HttpRequest();
48 | httpRequest.setUrl(url);
49 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
50 | httpRequest.addHeader(RequestHeaderKey.Content_TYPE, RequestHeaderValue.ContentType.JSON);
51 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
52 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.UPDATE);
53 | httpRequest.addParam(RequestBodyKey.BIZ_ATTR, request.getBizAttr());
54 |
55 | httpRequest.setMethod(HttpMethod.POST);
56 | httpRequest.setContentType(HttpContentType.APPLICATION_JSON);
57 | return httpClient.sendHttpRequest(httpRequest);
58 | }
59 |
60 | /**
61 | * 删除目录请求
62 | *
63 | * @param request
64 | * 删除目录请求
65 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功,
66 | * 其他为失败, message为success或者失败原因
67 | * @throws AbstractCosException
68 | * SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
69 | */
70 | public String delFolder(DelFolderRequest request) throws AbstractCosException {
71 | return super.delBase(request);
72 | }
73 |
74 | /**
75 | * 获取目录属性请求
76 | *
77 | * @param request
78 | * 获取目录属性请求
79 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功,
80 | * 其他为失败, message为success或者失败原因
81 | * @throws AbstractCosException
82 | * SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
83 | */
84 | public String statFolder(StatFolderRequest request) throws AbstractCosException {
85 | return super.statBase(request);
86 | }
87 |
88 | /**
89 | * 创建目录请求
90 | *
91 | * @param request
92 | * 创建目录属性请求
93 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功,
94 | * 其他为失败, message为success或者失败原因
95 | * @throws AbstractCosException
96 | * SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
97 | */
98 | public String createFolder(CreateFolderRequest request) throws AbstractCosException {
99 | request.check_param();
100 |
101 | String url = buildUrl(request);
102 | long signExpired = System.currentTimeMillis() / 1000 + this.config.getSignExpired();
103 | String sign = Sign.getPeriodEffectiveSign(request.getBucketName(), request.getCosPath(), this.cred, signExpired);
104 |
105 | HttpRequest httpRequest = new HttpRequest();
106 | httpRequest.setUrl(url);
107 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
108 | httpRequest.addHeader(RequestHeaderKey.Content_TYPE, RequestHeaderValue.ContentType.JSON);
109 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
110 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.CREATE);
111 | httpRequest.addParam(RequestBodyKey.BIZ_ATTR, request.getBizAttr());
112 |
113 | httpRequest.setMethod(HttpMethod.POST);
114 | httpRequest.setContentType(HttpContentType.APPLICATION_JSON);
115 | return httpClient.sendHttpRequest(httpRequest);
116 | }
117 |
118 | /**
119 | * 获取目录列表请求
120 | *
121 | * @param request
122 | * list目录属性请求
123 | * @return JSON格式的字符串, 格式为{"code":$code, "message":"$mess"}, code为0表示成功,
124 | * 其他为失败, message为success或者失败原因
125 | * @throws AbstractCosException
126 | * SDK定义的COS异常, 通常是输入参数有误或者环境问题(如网络不通)
127 | */
128 | public String listFolder(ListFolderRequest request) throws AbstractCosException {
129 |
130 | request.check_param();
131 | request.setCosPath(request.getCosPath() + request.getPrefix());
132 |
133 | String url = buildUrl(request);
134 | long signExpired = System.currentTimeMillis() / 1000 + this.config.getSignExpired();
135 | String sign = Sign.getPeriodEffectiveSign(request.getBucketName(), request.getCosPath(), this.cred, signExpired);
136 |
137 | HttpRequest httpRequest = new HttpRequest();
138 | httpRequest.setUrl(url);
139 | httpRequest.addHeader(RequestHeaderKey.Authorization, sign);
140 | httpRequest.addHeader(RequestHeaderKey.USER_AGENT, this.config.getUserAgent());
141 | httpRequest.addParam(RequestBodyKey.OP, RequestBodyValue.OP.LIST);
142 | httpRequest.addParam(RequestBodyKey.NUM, String.valueOf(request.getNum()));
143 | httpRequest.addParam(RequestBodyKey.LIST_FLAG, String.valueOf(request.getListFlag()));
144 | httpRequest.addParam(RequestBodyKey.CONTEXT, request.getContext());
145 | httpRequest.addParam(RequestBodyKey.DELIMITER, request.getDelimiter());
146 | httpRequest.setMethod(HttpMethod.GET);
147 |
148 | return httpClient.sendHttpRequest(httpRequest);
149 | }
150 |
151 | }
152 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/AbstractBaseRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 | /**
6 | * @author chengwu
7 | * 封装了请求包含的基本元素
8 | */
9 | public abstract class AbstractBaseRequest {
10 | // bucket名
11 | private String bucketName;
12 | // cos路径
13 | private String cosPath;
14 |
15 | public AbstractBaseRequest(String bucketName, String cosPath) {
16 | super();
17 | this.bucketName = bucketName;
18 | this.cosPath = cosPath;
19 | }
20 |
21 | // 获取bucket名
22 | public String getBucketName() {
23 | return bucketName;
24 | }
25 |
26 | // 设置bucket名
27 | public void setBucketName(String bucketName) {
28 | this.bucketName = bucketName;
29 | }
30 |
31 | // 获取cos_path
32 | public String getCosPath() {
33 | return cosPath;
34 | }
35 |
36 | // 设置cos_path
37 | public void setCosPath(String cosPath) {
38 | this.cosPath = cosPath;
39 | }
40 |
41 | protected String getMemberStringValue(String member) {
42 | if (member == null) {
43 | return "null";
44 | } else {
45 | return member;
46 | }
47 | }
48 |
49 | // 将request转换为字符串, 用于记录信息
50 | @Override
51 | public String toString() {
52 | StringBuilder sb = new StringBuilder();
53 | sb.append("bucketName:").append(getMemberStringValue(bucketName));
54 | sb.append(", cosPath:").append(getMemberStringValue(cosPath));
55 | return sb.toString();
56 | }
57 |
58 |
59 |
60 | // 检查用户的输入参数
61 | public void check_param() throws ParamException {
62 | CommonParamCheckUtils.AssertNotNull("bucketName", this.bucketName);
63 | CommonParamCheckUtils.AssertNotNull("cosPath", this.cosPath);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/AbstractDelRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | /**
4 | * @author chengwu
5 | * 删除文件请求
6 | */
7 | public class AbstractDelRequest extends AbstractBaseRequest {
8 |
9 | public AbstractDelRequest(String bucketName, String cosPath) {
10 | super(bucketName, cosPath);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/AbstractStatRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | /**
4 | * @author chengwu
5 | * 获取文件属性信息
6 | */
7 | public class AbstractStatRequest extends AbstractBaseRequest {
8 |
9 | public AbstractStatRequest(String bucketName, String cosPath) {
10 | super(bucketName, cosPath);
11 | }
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/CreateFolderRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu
8 | * 创建目录请求
9 | */
10 | public class CreateFolderRequest extends AbstractBaseRequest {
11 | // 目录属性,默认为空
12 | private String bizAttr = "";
13 |
14 | public CreateFolderRequest(String bucketName, String cosPath) {
15 | this(bucketName, cosPath, "");
16 | }
17 |
18 | public CreateFolderRequest(String bucketName, String cosPath, String bizAttr) {
19 | super(bucketName, cosPath);
20 | this.bizAttr = bizAttr;
21 | }
22 |
23 | public void setBizAttr(String bizAttr) {
24 | this.bizAttr = bizAttr;
25 | }
26 |
27 | public String getBizAttr() {
28 | return bizAttr;
29 | }
30 |
31 | @Override
32 | public void check_param() throws ParamException {
33 | super.check_param();
34 | CommonParamCheckUtils.AssertNotNull("bizAttr", this.bizAttr);
35 | CommonParamCheckUtils.AssertLegalCosFolderPath(this.getCosPath());
36 | CommonParamCheckUtils.AssertNotRootCosPath(this.getCosPath());
37 | }
38 |
39 | @Override
40 | public String toString() {
41 | StringBuilder sb = new StringBuilder();
42 | sb.append(super.toString());
43 | sb.append(", bizAttr:").append(getMemberStringValue(bizAttr));
44 | return sb.toString();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/DelFileRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu
8 | * 删除目录请求
9 | */
10 | public class DelFileRequest extends AbstractDelRequest {
11 |
12 | public DelFileRequest(String bucketName, String cosPath) {
13 | super(bucketName, cosPath);
14 | }
15 |
16 | @Override
17 | public void check_param() throws ParamException {
18 | super.check_param();
19 | CommonParamCheckUtils.AssertLegalCosFilePath(this.getCosPath());
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/DelFolderRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu
8 | * 删除文件请求
9 | */
10 | public class DelFolderRequest extends AbstractDelRequest {
11 |
12 | public DelFolderRequest(String bucketName, String cosPath) {
13 | super(bucketName, cosPath);
14 | }
15 |
16 | @Override
17 | public void check_param() throws ParamException {
18 | super.check_param();
19 | CommonParamCheckUtils.AssertLegalCosFolderPath(this.getCosPath());
20 | CommonParamCheckUtils.AssertNotRootCosPath(this.getCosPath());
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/GetFileInputStreamRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu 获取下载文件的输入流
8 | */
9 | public class GetFileInputStreamRequest extends AbstractBaseRequest {
10 |
11 | // 使用CDN加速下载,默认开启, 否则从COS源站进行下载
12 | private boolean useCDN = true;
13 |
14 | // referer设置, 如果没开启referer防盗链,可以不设置
15 | private String referer = "";
16 |
17 | // 下载文件的range的起始位置
18 | private long rangeStart = 0;
19 | // 下载文件的range的结束位置
20 | private long rangeEnd = Long.MAX_VALUE;
21 |
22 | public GetFileInputStreamRequest(String bucketName, String cosPath) {
23 | super(bucketName, cosPath);
24 | }
25 |
26 | @Override
27 | public void check_param() throws ParamException {
28 | super.check_param();
29 | CommonParamCheckUtils.AssertLegalCosFilePath(this.getCosPath());
30 | }
31 |
32 | public long getRangeStart() {
33 | return rangeStart;
34 | }
35 |
36 | public void setRangeStart(long rangeStart) {
37 | this.rangeStart = rangeStart;
38 | }
39 |
40 | public long getRangeEnd() {
41 | return rangeEnd;
42 | }
43 |
44 | public void setRangeEnd(long rangeEnd) {
45 | this.rangeEnd = rangeEnd;
46 | }
47 |
48 | public boolean isUseCDN() {
49 | return useCDN;
50 | }
51 |
52 | public void setUseCDN(boolean useCDN) {
53 | this.useCDN = useCDN;
54 | }
55 |
56 | public String getReferer() {
57 | return referer;
58 | }
59 |
60 | public void setReferer(String referer) {
61 | this.referer = referer;
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/GetFileLocalRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu 下载文件到本地请求
8 | */
9 | public class GetFileLocalRequest extends GetFileInputStreamRequest {
10 |
11 | // 要下载到的本地文件
12 | private String localPath = null;
13 |
14 | public GetFileLocalRequest(String bucketName, String cosPath, String localPath) {
15 | super(bucketName, cosPath);
16 | this.localPath = localPath;
17 | }
18 |
19 | public String getLocalPath() {
20 | return localPath;
21 | }
22 |
23 | public void setLocalPath(String localPath) {
24 | this.localPath = localPath;
25 | }
26 |
27 |
28 | @Override
29 | public void check_param() throws ParamException {
30 | super.check_param();
31 | CommonParamCheckUtils.AssertLegalCosFilePath(this.getCosPath());
32 | }
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/ListFolderRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu 获取目录成员请求
8 | */
9 | public class ListFolderRequest extends AbstractBaseRequest {
10 |
11 | // 默认获取的最大目录成员数量
12 | private final int DEFAULT_LIST_NUM = 199;
13 | private final int DEFAULT_LIST_FLAG = 1;
14 |
15 | private int num = DEFAULT_LIST_NUM;
16 | private int listFlag = DEFAULT_LIST_FLAG;
17 | private String context = "";
18 | private String prefix = "";
19 | private String delimiter = "/";
20 |
21 | public ListFolderRequest(String bucketName, String cosPath) {
22 | super(bucketName, cosPath);
23 | }
24 |
25 | public int getNum() {
26 | return num;
27 | }
28 |
29 | public void setNum(int num) {
30 | this.num = num;
31 | }
32 |
33 | public String getContext() {
34 | return context;
35 | }
36 |
37 | public void setContext(String context) {
38 | this.context = context;
39 | }
40 |
41 | public String getPrefix() {
42 | return prefix;
43 | }
44 |
45 | public void setPrefix(String prefix) {
46 | this.prefix = prefix;
47 | }
48 |
49 | public int getListFlag() {
50 | return listFlag;
51 | }
52 |
53 | public void setListFlag(int listFlag) {
54 | this.listFlag = listFlag;
55 | }
56 |
57 | public String getDelimiter() {
58 | return delimiter;
59 | }
60 |
61 | public void setDelimiter(String delimiter) {
62 | this.delimiter = delimiter;
63 | }
64 |
65 | @Override
66 | public void check_param() throws ParamException {
67 | super.check_param();
68 | CommonParamCheckUtils.AssertLegalCosFolderPath(getCosPath());
69 | CommonParamCheckUtils.AssertNotNull("context", this.context);
70 | }
71 |
72 | @Override
73 | public String toString() {
74 | StringBuilder sb = new StringBuilder();
75 | sb.append(super.toString());
76 | sb.append(", num:").append(this.num);
77 | sb.append(", context:").append(getMemberStringValue(this.context));
78 | sb.append(", listFlag:").append(this.listFlag);
79 | sb.append(", prefix:").append(getMemberStringValue(this.prefix));
80 | return sb.toString();
81 | }
82 |
83 | }
84 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/ListPartsRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | public class ListPartsRequest extends AbstractBaseRequest {
7 |
8 | public ListPartsRequest(String bucketName, String cosPath) {
9 | super(bucketName, cosPath);
10 | }
11 |
12 | @Override
13 | public void check_param() throws ParamException {
14 | super.check_param();
15 | CommonParamCheckUtils.AssertLegalCosFilePath(this.getCosPath());
16 | }
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/MoveFileRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 | import com.qcloud.cos.meta.OverWrite;
6 |
7 | public class MoveFileRequest extends AbstractBaseRequest {
8 | private String dstCosPath = "";
9 | private OverWrite overWrite = OverWrite.NO_OVER_WRITE;
10 |
11 | public MoveFileRequest(String bucketName, String cosPath, String dstCosPath) {
12 | super(bucketName, cosPath);
13 | this.dstCosPath = dstCosPath;
14 | }
15 |
16 | public String getDstCosPath() {
17 | return this.dstCosPath;
18 | }
19 |
20 | public void setDstCosPath(String dstCosPath) {
21 | this.dstCosPath = dstCosPath;
22 | }
23 |
24 | public OverWrite getOverWrite() {
25 | return overWrite;
26 | }
27 |
28 | public void setOverWrite(OverWrite overWrite) {
29 | this.overWrite = overWrite;
30 | }
31 |
32 | @Override
33 | public void check_param() throws ParamException {
34 | super.check_param();
35 | CommonParamCheckUtils.AssertLegalCosFilePath(this.getCosPath());
36 | CommonParamCheckUtils.AssertLegalCosFilePath(this.dstCosPath);
37 | CommonParamCheckUtils.AssertNotNull("overWrite", this.overWrite);
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/StatFileRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu
8 | * 获取文件属性信息
9 | */
10 | public class StatFileRequest extends AbstractStatRequest {
11 |
12 | public StatFileRequest(String bucketName, String cosPath) {
13 | super(bucketName, cosPath);
14 | }
15 |
16 | @Override
17 | public void check_param() throws ParamException {
18 | super.check_param();
19 | CommonParamCheckUtils.AssertLegalCosFilePath(this.getCosPath());
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/StatFolderRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu
8 | * 获取目录属性信息
9 | */
10 | public class StatFolderRequest extends AbstractStatRequest {
11 |
12 | public StatFolderRequest(String bucketName, String cosPath) {
13 | super(bucketName, cosPath);
14 | }
15 |
16 | @Override
17 | public void check_param() throws ParamException {
18 | super.check_param();
19 | CommonParamCheckUtils.AssertLegalCosFolderPath(this.getCosPath());
20 | }
21 |
22 | }
23 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/UpdateFileRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import java.util.HashMap;
4 | import java.util.Map;
5 |
6 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
7 | import com.qcloud.cos.exception.ParamException;
8 | import com.qcloud.cos.meta.FileAuthority;
9 |
10 | /**
11 | * @author chengwu 更新文件请求
12 | *
13 | */
14 | public class UpdateFileRequest extends AbstractBaseRequest {
15 | // 用户更新标识,更新bizAttr是0x01, 更新authority0x80, 更新custom_httpheader是0x40
16 | // 更新多个属性是这些这些值取或
17 | private int updatFlag = 0;
18 |
19 | // biz_attr属性
20 | private String bizAttr = "";
21 | // 权限
22 | private FileAuthority authority = FileAuthority.INVALID;
23 | // HTTP Cache-Control属性
24 | private String cacheControl = "";
25 | // HTTP Content-Type属性
26 | private String contentType = "";
27 | // HTTP Content-Disposition属性
28 | private String contentDisposition = "";
29 | // HTTP Content-Language属性
30 | private String contentLanguage = "";
31 | // HTTP Content-Encoding属性
32 | private String contentEncoding = "";
33 | // 自定义http头
34 | private Map customHeaders = new HashMap();
35 | // 自定义http头, key为x-cos-meta-开头, value为字符串
36 | private Map xCosMetaHeaders = new HashMap();
37 |
38 | public UpdateFileRequest(String bucketName, String cosPath) {
39 | super(bucketName, cosPath);
40 | }
41 |
42 | public int getUpdateFlag() {
43 | return updatFlag;
44 | }
45 |
46 | public String getBizAttr() {
47 | return bizAttr;
48 | }
49 |
50 | public void setBizAttr(String bizAttr) {
51 | this.bizAttr = bizAttr;
52 | this.updatFlag |= 0x01;
53 | }
54 |
55 | public FileAuthority getAuthority() {
56 | return authority;
57 | }
58 |
59 | public void setAuthority(FileAuthority authority) {
60 | this.authority = authority;
61 | this.updatFlag |= 0x80;
62 | }
63 |
64 | public Map getCustomHeaders() {
65 | return customHeaders;
66 | }
67 |
68 | public void setCacheControl(String cacheControl) {
69 | this.cacheControl = cacheControl;
70 | this.updatFlag |= 0x40;
71 | this.customHeaders.put("Cache-Control", cacheControl);
72 | }
73 |
74 | public void setContentType(String contentType) {
75 | this.contentType = contentType;
76 | this.updatFlag |= 0x40;
77 | this.customHeaders.put("Content-Type", contentType);
78 | }
79 |
80 | public void setContentDisposition(String contentDisposition) {
81 | this.contentDisposition = contentDisposition;
82 | this.updatFlag |= 0x40;
83 | this.customHeaders.put("Content-Disposition", contentDisposition);
84 | }
85 |
86 | public void setContentLanguage(String contentLanguage) {
87 | this.contentLanguage = contentLanguage;
88 | this.updatFlag |= 0x40;
89 | this.customHeaders.put("Content-Language", contentLanguage);
90 | }
91 |
92 |
93 | public void setContentEncoding(String contentEncoding) {
94 | this.contentEncoding = contentEncoding;
95 | this.updatFlag |= 0x40;
96 | this.customHeaders.put("Content-Encoding", contentEncoding);
97 | }
98 |
99 | public void setXCosMeta(String key, String value) {
100 | this.xCosMetaHeaders.put(key, value);
101 | this.customHeaders.put(key, value);
102 | this.updatFlag |= 0x40;
103 | }
104 |
105 | @Override
106 | public void check_param() throws ParamException {
107 | super.check_param();
108 | CommonParamCheckUtils.AssertLegalCosFilePath(this.getCosPath());
109 | CommonParamCheckUtils.AssertLegalUpdateFlag(this.updatFlag);
110 | CommonParamCheckUtils.AssertNotNull("biz_attr", this.bizAttr);
111 | CommonParamCheckUtils.AssertNotNull("authority", this.authority);
112 | CommonParamCheckUtils.AssertNotNull("cacheControl", this.cacheControl);
113 | CommonParamCheckUtils.AssertNotNull("contentType", this.contentType);
114 | CommonParamCheckUtils.AssertNotNull("contentDisposition", this.contentDisposition);
115 | CommonParamCheckUtils.AssertNotNull("contentLanguage", this.contentLanguage);
116 | CommonParamCheckUtils.AssertNotNull("contentEncoding", this.contentEncoding);
117 | CommonParamCheckUtils.AssertLegalXCosMeta(this.xCosMetaHeaders);
118 | }
119 |
120 | @Override
121 | public String toString() {
122 | StringBuilder sb = new StringBuilder();
123 | sb.append(super.toString());
124 | sb.append(", biz_attr:").append(getMemberStringValue(bizAttr));
125 | sb.append(", authority:").append(this.authority);
126 | sb.append(", cacheControl:").append(getMemberStringValue(this.cacheControl));
127 | sb.append(", contentType:").append(getMemberStringValue(this.contentType));
128 | sb.append(", contentDisposition:").append(getMemberStringValue(this.contentDisposition));
129 | sb.append(", contentLanguage:").append(getMemberStringValue(this.contentLanguage));
130 | sb.append(", contentEncoding:").append(getMemberStringValue(this.contentEncoding));
131 | for (String key : this.xCosMetaHeaders.keySet()) {
132 | sb.append(", x_cos_meta_key:").append(getMemberStringValue(key));
133 | sb.append(", x_cos_meta_value:")
134 | .append(getMemberStringValue(this.xCosMetaHeaders.get(key)));
135 | }
136 | sb.append(", authority:");
137 | if (this.authority == null) {
138 | sb.append("null");
139 | } else {
140 | sb.append(this.authority);
141 | }
142 | return sb.toString();
143 | }
144 | }
145 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/UpdateFolderRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu 更新目录请求
8 | *
9 | */
10 | public class UpdateFolderRequest extends AbstractBaseRequest {
11 |
12 | // biz_attr属性
13 | private String bizAttr = "";
14 |
15 | public UpdateFolderRequest(String bucketName, String cosPath) {
16 | super(bucketName, cosPath);
17 | }
18 |
19 | public String getBizAttr() {
20 | return bizAttr;
21 | }
22 |
23 | public void setBizAttr(String bizAttr) {
24 | this.bizAttr = bizAttr;
25 | }
26 |
27 | @Override
28 | public void check_param() throws ParamException {
29 | super.check_param();
30 | CommonParamCheckUtils.AssertLegalCosFolderPath(this.getCosPath());
31 | CommonParamCheckUtils.AssertNotRootCosPath(this.getCosPath());
32 | CommonParamCheckUtils.AssertNotNull("biz_attr", this.bizAttr);
33 | }
34 |
35 | @Override
36 | public String toString() {
37 | StringBuilder sb = new StringBuilder();
38 | sb.append(super.toString());
39 | sb.append(", biz_attr:").append(getMemberStringValue(bizAttr));
40 | return sb.toString();
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/UploadFileRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 | import com.qcloud.cos.meta.InsertOnly;
6 |
7 | /**
8 | * @author chengwu 上传文件请求,针对文件整体上传,不分片的操作
9 | */
10 | public class UploadFileRequest extends AbstractBaseRequest {
11 | // 默认最大并发度,这里是16个线程并发发送
12 | private static final int DEFAULT_TASK_NUM = 16;
13 | // 需要上传的路径
14 | private String localPath;
15 | // 上传文件的属性信息
16 | private String bizAttr;
17 |
18 | private byte[] contentBufer = null;
19 | private boolean uploadFromBuffer = false;
20 |
21 | private InsertOnly insertOnly = InsertOnly.NO_OVER_WRITE;
22 |
23 | // 开启sha摘要
24 | protected boolean enableShaDigest = false;
25 |
26 | // 并行任务数
27 | protected int taskNum = DEFAULT_TASK_NUM;
28 |
29 | public UploadFileRequest(String bucketName, String cosPath, String localPath, String bizAttr) {
30 | super(bucketName, cosPath);
31 | this.localPath = localPath;
32 | this.bizAttr = bizAttr;
33 | this.contentBufer = null;
34 | this.uploadFromBuffer = false;
35 | }
36 |
37 | public UploadFileRequest(String bucketName, String cosPath, String localPath) {
38 | this(bucketName, cosPath, localPath, "");
39 | }
40 |
41 | public UploadFileRequest(String bucketName, String cosPath, byte[] contentBuffer) {
42 | super(bucketName, cosPath);
43 | this.contentBufer = contentBuffer;
44 | this.uploadFromBuffer = true;
45 | this.bizAttr = "";
46 | }
47 |
48 | public String getBizAttr() {
49 | return bizAttr;
50 | }
51 |
52 | public void setBizAttr(String bizAttr) {
53 | this.bizAttr = bizAttr;
54 | }
55 |
56 | public String getLocalPath() {
57 | return localPath;
58 | }
59 |
60 | public void setLocalPath(String localPath) {
61 | this.localPath = localPath;
62 | this.uploadFromBuffer = false;
63 | }
64 |
65 | public InsertOnly getInsertOnly() {
66 | return insertOnly;
67 | }
68 |
69 | public void setInsertOnly(InsertOnly insertOnly) {
70 | this.insertOnly = insertOnly;
71 | }
72 |
73 | public byte[] getContentBufer() {
74 | return contentBufer;
75 | }
76 |
77 | public void setContentBufer(byte[] contentBufer) {
78 | this.contentBufer = contentBufer;
79 | this.uploadFromBuffer = true;
80 | }
81 |
82 | public boolean isUploadFromBuffer() {
83 | return uploadFromBuffer;
84 | }
85 |
86 |
87 | @Override
88 | public void check_param() throws ParamException {
89 | super.check_param();
90 | CommonParamCheckUtils.AssertLegalCosFilePath(this.getCosPath());
91 | CommonParamCheckUtils.AssertNotNull("biz_attr", this.bizAttr);
92 | CommonParamCheckUtils.AssertNotNull("insertOnly", this.insertOnly);
93 | if (!this.uploadFromBuffer) {
94 | CommonParamCheckUtils.AssertLegalLocalFilePath(this.localPath);
95 | } else {
96 | CommonParamCheckUtils.AssertNotNull("contentBufer", contentBufer);
97 | }
98 | }
99 |
100 | public int getTaskNum() {
101 | return taskNum;
102 | }
103 |
104 | public void setTaskNum(int taskNum) {
105 | this.taskNum = taskNum;
106 | }
107 |
108 | public boolean isEnableShaDigest() {
109 | return enableShaDigest;
110 | }
111 |
112 | public void setEnableShaDigest(boolean enableShaDigest) {
113 | this.enableShaDigest = enableShaDigest;
114 | }
115 |
116 | @Override
117 | public String toString() {
118 | StringBuilder sb = new StringBuilder();
119 | sb.append(super.toString());
120 | sb.append(", local_path:").append(getMemberStringValue(this.localPath));
121 | sb.append(", bizAttr:").append(getMemberStringValue(this.bizAttr));
122 | sb.append(", uploadFromBuffer:").append(this.uploadFromBuffer);
123 | sb.append(", insertonly:");
124 | if (this.insertOnly == null) {
125 | sb.append("null");
126 | } else {
127 | sb.append(this.insertOnly.ordinal());
128 | }
129 | return sb.toString();
130 | }
131 | }
132 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/request/UploadSliceFileRequest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.request;
2 |
3 | import com.qcloud.cos.common_utils.CommonParamCheckUtils;
4 | import com.qcloud.cos.exception.ParamException;
5 |
6 | /**
7 | * @author chengwu 文件分片上传请求
8 | */
9 | public class UploadSliceFileRequest extends UploadFileRequest {
10 | // 默认分片大小1MB
11 | private static final int DEFAULT_SLICE_SIZE = 1024 * 1024;
12 | // 分片大小,单位字节
13 | private int sliceSize = DEFAULT_SLICE_SIZE;
14 |
15 | public UploadSliceFileRequest(UploadFileRequest request) {
16 | super(request.getBucketName(), request.getCosPath(), request.getLocalPath(),
17 | request.getBizAttr());
18 | }
19 |
20 | public UploadSliceFileRequest(String bucketName, String cosPath, String localPath,
21 | int sliceSize) {
22 | super(bucketName, cosPath, localPath);
23 | this.sliceSize = sliceSize;
24 | }
25 |
26 | public UploadSliceFileRequest(String bucketName, String cosPath, byte[] contentBuffer) {
27 | super(bucketName, cosPath, contentBuffer);
28 | }
29 |
30 | public int getSliceSize() {
31 | return sliceSize;
32 | }
33 |
34 | public void setSliceSize(int sliceSize) {
35 | this.sliceSize = sliceSize;
36 | }
37 |
38 | @Override
39 | public void check_param() throws ParamException {
40 | super.check_param();
41 | CommonParamCheckUtils.AssertLegalSliceSize(this.sliceSize);
42 | }
43 |
44 | @Override
45 | public String toString() {
46 | StringBuilder sb = new StringBuilder();
47 | sb.append(super.toString());
48 | sb.append(", sliceSize:").append(this.sliceSize);
49 | sb.append(", taskNum:").append(String.valueOf(this.taskNum));
50 | sb.append(", enableShaDigest:");
51 | if (enableShaDigest) {
52 | sb.append("1");
53 | } else {
54 | sb.append("0");
55 | }
56 | return sb.toString();
57 | }
58 |
59 | }
60 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/sign/Credentials.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.sign;
2 |
3 | /**
4 | * @author chengwu
5 | * 鉴权信息, 包括appId, 密钥对
6 | */
7 | public class Credentials {
8 | private final long appId;
9 | private final String secretId;
10 | private final String secretKey;
11 |
12 | public Credentials(long appId, String secretId, String secretKey) {
13 | super();
14 | this.appId = appId;
15 | this.secretId = secretId;
16 | this.secretKey = secretKey;
17 | }
18 |
19 | public long getAppId() {
20 | return appId;
21 | }
22 |
23 | public String getSecretId() {
24 | return secretId;
25 | }
26 |
27 | public String getSecretKey() {
28 | return secretKey;
29 | }
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/src/main/java/com/qcloud/cos/sign/Sign.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.sign;
2 |
3 | import java.util.Random;
4 |
5 | import com.qcloud.cos.common_utils.CommonCodecUtils;
6 | import com.qcloud.cos.common_utils.CommonPathUtils;
7 | import com.qcloud.cos.exception.AbstractCosException;
8 | import com.qcloud.cos.exception.UnknownException;
9 |
10 | /**
11 | * @author chengwu 封装签名类,包括单次,多次以及下载签名
12 | */
13 | public class Sign {
14 | private static final Random randomGenerator = new Random();
15 |
16 | /**
17 | * 返回用户访问资源的签名
18 | *
19 | * @param cred
20 | * 包含用户秘钥信息
21 | * @param bucketName
22 | * bucket名
23 | * @param cosPath
24 | * 要签名的cos路径
25 | * @param expired
26 | * 超时时间
27 | * @param uploadFlag
28 | * 除了生成下载签名,其他情况updateFlag皆为true
29 | * @return 返回base64编码的字符串
30 | * @throws AbstractCosException
31 | */
32 | private static String appSignatureBase(Credentials cred, String bucketName, String cosPath, long expired,
33 | boolean uploadFlag) throws AbstractCosException {
34 | long appId = cred.getAppId();
35 | String secretId = cred.getSecretId();
36 | String secretKey = cred.getSecretKey();
37 | long now = System.currentTimeMillis() / 1000;
38 | int rdm = Math.abs(randomGenerator.nextInt());
39 | String fileId = null;
40 | if (uploadFlag) {
41 | fileId = String.format("/%d/%s%s", appId, bucketName, cosPath);
42 | } else {
43 | fileId = cosPath;
44 | }
45 | fileId = CommonPathUtils.encodeRemotePath(fileId);
46 | String plainText = String.format("a=%s&k=%s&e=%d&t=%d&r=%d&f=%s&b=%s", appId, secretId, expired, now, rdm,
47 | fileId, bucketName);
48 |
49 | byte[] hmacDigest;
50 | try {
51 | hmacDigest = CommonCodecUtils.HmacSha1(plainText, secretKey);
52 | } catch (Exception e) {
53 | throw new UnknownException(e.getMessage());
54 | }
55 | byte[] signContent = new byte[hmacDigest.length + plainText.getBytes().length];
56 | System.arraycopy(hmacDigest, 0, signContent, 0, hmacDigest.length);
57 | System.arraycopy(plainText.getBytes(), 0, signContent, hmacDigest.length, plainText.getBytes().length);
58 |
59 | return CommonCodecUtils.Base64Encode(signContent);
60 | }
61 |
62 | /**
63 | * 获取多次签名, 一段时间内有效, 针对上传文件,重命名文件, 创建目录, 获取文件目录属性, 拉取目录列表
64 | *
65 | * @param bucketName
66 | * bucket名称
67 | * @param cosPath
68 | * 要签名的cos路径
69 | * @param cred
70 | * 用户的身份信息, 包括appid, secret_id和secret_key
71 | * @param expired
72 | * 签名过期时间, UNIX时间戳。如想让签名在30秒后过期, 即可将expired设成当前时间加上30秒
73 | * @return base64编码的字符串
74 | * @throws AbstractCosException
75 | */
76 | public static String getPeriodEffectiveSign(String bucketName, String cosPath, Credentials cred, long expired)
77 | throws AbstractCosException {
78 | return appSignatureBase(cred, bucketName, cosPath, expired, true);
79 | }
80 |
81 | /**
82 | * 获取单次签名, 一次有效,针对删除和更新文件目录
83 | *
84 | * @param bucketName
85 | * bucket名称
86 | * @param cosPath
87 | * 要签名的cos路径
88 | * @param cred
89 | * 用户的身份信息, 包括appid, secret_id和secret_key
90 | * @return base64编码的字符串
91 | * @throws AbstractCosException
92 | */
93 | public static String getOneEffectiveSign(String bucketName, String cosPath, Credentials cred)
94 | throws AbstractCosException {
95 | return appSignatureBase(cred, bucketName, cosPath, 0, true);
96 | }
97 |
98 | /**
99 | * 下载签名, 用于获取后拼接成下载链接,下载私有bucket的文件
100 | *
101 | * @param bucketName
102 | * bucket名称
103 | * @param cosPath
104 | * 要签名的cos路径
105 | * @param cred
106 | * 用户的身份信息, 包括appid, secret_id和secret_key
107 | * @param expired
108 | * 签名过期时间, UNIX时间戳。如想让签名在30秒后过期, 即可将expired设成当前时间加上30秒
109 | * @return base64编码的字符串
110 | * @throws AbstractCosException
111 | */
112 | public static String getDownLoadSign(String bucketName, String cosPath, Credentials cred, long expired)
113 | throws AbstractCosException {
114 | return appSignatureBase(cred, bucketName, cosPath, expired, false);
115 | }
116 |
117 | }
118 |
--------------------------------------------------------------------------------
/src/test/java/com/qcloud/cos/common_utils/CommonCodecUtilsTest.java:
--------------------------------------------------------------------------------
1 | package com.qcloud.cos.common_utils;
2 |
3 | import static org.junit.Assert.*;
4 |
5 | import org.junit.Test;
6 |
7 | import com.qcloud.cos.common_utils.CommonCodecUtils;
8 |
9 | public class CommonCodecUtilsTest {
10 |
11 | private static final String plainText = "681805d9f7c6ab988a00c02f1096b1b68a77aaed";
12 | private static final String hmacKey = "lw7231!2@7g";
13 |
14 | @Test
15 | public void testBase64Encode() {
16 | try {
17 | String encodeStr = CommonCodecUtils.Base64Encode(plainText.getBytes("UTF-8"));
18 | String expectEncodeStr = "NjgxODA1ZDlmN2M2YWI5ODhhMDBjMDJmMTA5NmIxYjY4YTc3YWFlZA==";
19 | boolean cmpResult = encodeStr.equals(expectEncodeStr);
20 | assertTrue(cmpResult);
21 | } catch (Exception e) {
22 | fail();
23 | }
24 | }
25 |
26 | @Test
27 | public void testHmacSha1StringString() {
28 | try {
29 | byte[] hmacDigestByte = CommonCodecUtils.HmacSha1(plainText, hmacKey);
30 | StringBuilder stringBuilder = new StringBuilder();
31 | for (int i = 0; i < hmacDigestByte.length; ++i) {
32 | String hex = Integer.toHexString(hmacDigestByte[i] & 0xff);
33 | if (hex.length() == 1) {
34 | stringBuilder.append("0");
35 | }
36 | stringBuilder.append(hex);
37 | }
38 | String expectHmacDigest = "e8d7985289f8586a7bd2374590db848c48046874";
39 | assertTrue(expectHmacDigest.equals(stringBuilder.toString()));
40 | } catch (Exception e) {
41 | fail();
42 | }
43 | }
44 |
45 | }
46 |
--------------------------------------------------------------------------------
/src/test/resources/bigfile.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tencentyun/cos-java-sdk-v4/dec54d566b09ed8795de5d6d07d7b36a2076159f/src/test/resources/bigfile.txt
--------------------------------------------------------------------------------
/src/test/resources/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tencentyun/cos-java-sdk-v4/dec54d566b09ed8795de5d6d07d7b36a2076159f/src/test/resources/empty.txt
--------------------------------------------------------------------------------
/src/test/resources/local_file_1.txt:
--------------------------------------------------------------------------------
1 | 18544556699
--------------------------------------------------------------------------------
/src/test/resources/local_file_2.txt:
--------------------------------------------------------------------------------
1 | 15033556677
--------------------------------------------------------------------------------
/src/test/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
--------------------------------------------------------------------------------