在业务中需要储存一些文件到储存桶上,在上传下载中存储地址难免暴露在外,在设置储存桶私有访问后需要携带签名访问。签名可分为永久签名-临时签名,更推荐使用临时签名更加安全。
生成临时签名:
1.生成临时密钥
- 使用临时秘钥生成预签名,通过临时授权的方式进一步提高预签名上传、下载等请求的安全性。
- 如果您一定要使用永久密钥来生成预签名,建议永久密钥的权限范围仅限于上传或下载操作,以规避风险。(永久签名方法这里暂不提供需要留言或者去官方文档看)
- 获取签名/预签名函数,默认签入 Header Host;您也可以选择不签入 Header Host,但可能导致请求失败或安全漏洞。
- 引入依赖
-
<dependencies> <!--腾讯云 COS--> <dependency> <groupId>com.qcloud</groupId> <artifactId>cos_api</artifactId> <version>${qcloud.cos.version}</version> </dependency> <!--腾讯云 COS 临时秘钥生成--> <dependency> <groupId>com.qcloud</groupId> <artifactId>cos-sts_api</artifactId> <version>${cos.sts.version}</version> </dependency> </dependencies>
package com.qpyx.oss.utils;
import com.tencent.cloud.CosStsClient;
import com.tencent.cloud.Response;
import java.util.TreeMap;
public class TemporarySecretKey {
/**
* 获取临时密钥
* */
public static Response getTemporarySecretKey (){
TreeMap<String, Object> config = new TreeMap<String, Object>();
try {
//这里的 SecretId 和 SecretKey 代表了用于申请临时密钥的永久身份(主账号、子账号等),子账号需要具有操作存储桶的权限。
// 替换为您的云 api 密钥 SecretId
config.put("secretId", "这里填你自己储存桶 SecretId");
// 替换为您的云 api 密钥 SecretKey
config.put("secretKey", "这里填你自己储存桶 SecretKey");
// 设置域名:
// 如果您使用了腾讯云 cvm,可以设置内部域名
//config.put("host", "sts.internal.tencentcloudapi.com");
// 临时密钥有效时长,单位是秒,默认 1800 秒,目前主账号最长 2 小时(即 7200 秒),子账号最长 36 小时(即 129600)秒 这里设置60秒
config.put("durationSeconds", 60);
// 换成您的 bucket 例如 test-1300632903
config.put("bucket", "这里填你的桶名称");
// 换成 bucket 所在地区
config.put("region", "ap-guangzhou");
// 这里改成允许的路径前缀,可以根据自己网站的用户登录态判断允许上传的具体路径
// 列举几种典型的前缀授权场景:
// 1、允许访问所有对象:"*"
// 2、允许访问指定的对象:"a/a1.txt", "b/b1.txt"
// 3、允许访问指定前缀的对象:"a*", "a/*", "b/*"
// 如果填写了“*”,将允许用户访问所有资源;除非业务需要,否则请按照最小权限原则授予用户相应的访问权限范围。
config.put("allowPrefixes", new String[] {
"a*"
});
// 密钥的权限列表。必须在这里指定本次临时密钥所需要的权限。
// 简单上传、表单上传和分块上传需要以下的权限,其他权限列表请看 https://cloud.tencent.com/document/product/436/31923
String[] allowActions = new String[] {
// 简单上传
"name/cos:PutObject",
// 表单上传、小程序上传
"name/cos:PostObject",
// 分块上传
"name/cos:InitiateMultipartUpload",
"name/cos:ListMultipartUploads",
"name/cos:ListParts",
"name/cos:UploadPart",
"name/cos:CompleteMultipartUpload"
};
config.put("allowActions", allowActions);
return CosStsClient.getCredential(config);
} catch (Exception e) {
e.printStackTrace();
throw new IllegalArgumentException("no valid secret !");
}
}
}
2.引入签名sdk
使用腾讯云对象存储(Cloud Object Storage,COS)时,可通过 RESTful API 对 COS 发起 HTTP 匿名请求或 HTTP 签名请求,对于签名请求,COS 服务器端将会进行对请求发起者的身份验证。
- 匿名请求:HTTP 请求不携带任何身份标识和鉴权信息,通过 RESTful API 进行 HTTP 请求操作。
- 签名请求:HTTP 请求时携带签名,COS 服务器端收到消息后,进行身份验证,验证成功则可接受并执行请求,否则将会返回错误信息并丢弃此请求。
package com.qpyx.oss.utils;
import static com.qcloud.cos.auth.COSSignerConstants.LINE_SEPARATOR;
import static com.qcloud.cos.auth.COSSignerConstants.Q_AK;
import static com.qcloud.cos.auth.COSSignerConstants.Q_HEADER_LIST;
import static com.qcloud.cos.auth.COSSignerConstants.Q_KEY_TIME;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGNATURE;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_ALGORITHM_KEY;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_ALGORITHM_VALUE;
import static com.qcloud.cos.auth.COSSignerConstants.Q_SIGN_TIME;
import static com.qcloud.cos.auth.COSSignerConstants.Q_URL_PARAM_LIST;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import com.qcloud.cos.Headers;
import com.qcloud.cos.auth.AnonymousCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.auth.COSSessionCredentials;
import com.qcloud.cos.exception.CosClientException;
import com.qcloud.cos.http.CosHttpRequest;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.internal.CosServiceRequest;
import com.qcloud.cos.utils.UrlEncoderUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.codec.digest.HmacUtils;
/**
*签名生成工具
* */
public class COSSigner {
private static Set<String> needSignedHeaderSet = new HashSet<>();
private Boolean isCIWorkflowRequest = false;
// Time offset between local and server
private int localTimeDelta = 0;
static {
needSignedHeaderSet.add("cache-control");
needSignedHeaderSet.add("content-disposition");
needSignedHeaderSet.add("content-encoding");
needSignedHeaderSet.add("content-length");
needSignedHeaderSet.add("content-md5");
needSignedHeaderSet.add("content-type");
needSignedHeaderSet.add("expect");
needSignedHeaderSet.add("expires");
needSignedHeaderSet.add("host");
needSignedHeaderSet.add("if-match");
needSignedHeaderSet.add("if-modified-since");
needSignedHeaderSet.add("if-none-match");
needSignedHeaderSet.add("if-unmodified-since");
needSignedHeaderSet.add("origin");
needSignedHeaderSet.add("range");
needSignedHeaderSet.add("response-cache-control");
needSignedHeaderSet.add("response-content-disposition");
needSignedHeaderSet.add("response-content-encoding");
needSignedHeaderSet.add("response-content-language");
needSignedHeaderSet.add("response-content-type");
needSignedHeaderSet.add("response-expires");
needSignedHeaderSet.add("transfer-encoding");
needSignedHeaderSet.add("versionid");
}
private boolean isAnonymous(COSCredentials cred) {
return cred instanceof AnonymousCOSCredentials;
}
public <X extends CosServiceRequest> void sign(CosHttpRequest<X> request, COSCredentials cred, Date expiredTime) {
if (isAnonymous(cred)) {
return;
}
String authoriationStr =
buildAuthorizationStr(request.getHttpMethod(), request.getResourcePath(),
request.getHeaders(), request.getParameters(), cred, expiredTime, true);
request.addHeader(Headers.COS_AUTHORIZATION, authoriationStr);
if (cred instanceof COSSessionCredentials) {
request.addHeader(Headers.SECURITY_TOKEN,
((COSSessionCredentials) cred).getSessionToken());
}
}
public String buildPostObjectSignature(String secretKey, String keyTime, String policy) {
String signKey = HmacUtils.hmacSha1Hex(secretKey, keyTime);
String stringToSign = DigestUtils.sha1Hex(policy);
return HmacUtils.hmacSha1Hex(signKey, stringToSign);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
COSCredentials cred,
Date expiredTime) {
Date startTime = new Date();
return buildAuthorizationStr(methodName, resouce_path, new HashMap<>(), new HashMap<>(),
cred, startTime, expiredTime, true);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
Map<String, String> headerMap, Map<String, String> paramMap, COSCredentials cred,
Date expiredTime) {
Date startTime = new Date();
return buildAuthorizationStr(methodName, resouce_path, headerMap, paramMap,
cred, startTime, expiredTime,true);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
Map<String, String> headerMap, Map<String, String> paramMap, COSCredentials cred,
Date expiredTime, Boolean signHost) {
Date startTime = new Date();
return buildAuthorizationStr(methodName, resouce_path, headerMap, paramMap,
cred, startTime, expiredTime, signHost);
}
public String buildAuthorizationStr(HttpMethodName methodName, String resouce_path,
Map<String, String> headerMap, Map<String, String> paramMap, COSCredentials cred,
Date startTime, Date expiredTime, Boolean signHost) {
if (isAnonymous(cred)) {
return null;
}
//万象工作流接口会出现uri带问号的情况 例如 /workflow/xxxxxx?active 这种情况?后面的参数不参与鉴权
if (isCIWorkflowRequest){
resouce_path = resouce_path.split("\\?")[0];
}
Map<String, String> signHeaders = buildSignHeaders(headerMap, signHost);
// 签名中的参数和http 头部 都要进行字符串排序
TreeMap<String, String> sortedSignHeaders = new TreeMap<>();
TreeMap<String, String> sortedParams = new TreeMap<>();
sortedSignHeaders.putAll(signHeaders);
sortedParams.putAll(paramMap);
String qHeaderListStr = buildSignMemberStr(sortedSignHeaders);
String qUrlParamListStr = buildSignMemberStr(sortedParams);
String qKeyTimeStr, qSignTimeStr;
qKeyTimeStr = qSignTimeStr = buildTimeStr(startTime, expiredTime);
String signKey = HmacUtils.hmacSha1Hex(cred.getCOSSecretKey(), qKeyTimeStr);
String formatMethod = methodName.toString().toLowerCase();
String formatUri = resouce_path;
String formatParameters = formatMapToStr(sortedParams);
String formatHeaders = formatMapToStr(sortedSignHeaders);
String formatStr = new StringBuilder().append(formatMethod).append(LINE_SEPARATOR)
.append(formatUri).append(LINE_SEPARATOR).append(formatParameters)
.append(LINE_SEPARATOR).append(formatHeaders).append(LINE_SEPARATOR).toString();
String hashFormatStr = DigestUtils.sha1Hex(formatStr);
String stringToSign = new StringBuilder().append(Q_SIGN_ALGORITHM_VALUE)
.append(LINE_SEPARATOR).append(qSignTimeStr).append(LINE_SEPARATOR)
.append(hashFormatStr).append(LINE_SEPARATOR).toString();
String signature = HmacUtils.hmacSha1Hex(signKey, stringToSign);
String authoriationStr = new StringBuilder().append(Q_SIGN_ALGORITHM_KEY).append("=")
.append(Q_SIGN_ALGORITHM_VALUE).append("&").append(Q_AK).append("=")
.append(cred.getCOSAccessKeyId()).append("&").append(Q_SIGN_TIME).append("=")
.append(qSignTimeStr).append("&").append(Q_KEY_TIME).append("=").append(qKeyTimeStr)
.append("&").append(Q_HEADER_LIST).append("=").append(qHeaderListStr).append("&")
.append(Q_URL_PARAM_LIST).append("=").append(qUrlParamListStr).append("&")
.append(Q_SIGNATURE).append("=").append(signature).toString();
return authoriationStr;
}
public boolean needSignedHeader(String header) {
return needSignedHeaderSet.contains(header) || header.startsWith("x-cos-");
}
private Map<String, String> buildSignHeaders(Map<String, String> originHeaders, Boolean signHost) {
Boolean hasHost = false;
Map<String, String> signHeaders = new HashMap<>();
for (Entry<String, String> headerEntry : originHeaders.entrySet()) {
String key = headerEntry.getKey().toLowerCase();
if (key.equals("host")) {
hasHost = true;
}
if(needSignedHeader(key)) {
String value = headerEntry.getValue();
signHeaders.put(key, value);
}
}
if (!hasHost && signHost) {
String msg = String.format("buildAuthorization missing header: host. %s", originHeaders);
throw new CosClientException(msg);
}
return signHeaders;
}
private String buildSignMemberStr(Map<String, String> signHeaders) {
StringBuilder strBuilder = new StringBuilder();
boolean seenOne = false;
for (String key : signHeaders.keySet()) {
if (!seenOne) {
seenOne = true;
} else {
strBuilder.append(";");
}
strBuilder.append(UrlEncoderUtils.encode(key).toLowerCase());
}
return strBuilder.toString();
}
private String formatMapToStr(Map<String, String> kVMap) {
StringBuilder strBuilder = new StringBuilder();
boolean seeOne = false;
for (Entry<String, String> entry : kVMap.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
String encodeKey = UrlEncoderUtils.encode(key);
String lowerEncodeKey = encodeKey.toLowerCase();
String encodedValue = "";
if (value != null) {
encodedValue = UrlEncoderUtils.encode(value);
}
if (!seeOne) {
seeOne = true;
} else {
strBuilder.append("&");
}
strBuilder.append(lowerEncodeKey).append("=").append(encodedValue);
}
return strBuilder.toString();
}
private String buildTimeStr(Date startTime, Date endTime) {
StringBuilder strBuilder = new StringBuilder();
long startTimestamp = startTime.getTime() / 1000 + localTimeDelta;
long endTimestamp = endTime.getTime() / 1000 + localTimeDelta;
strBuilder.append(startTimestamp).append(";").append(endTimestamp);
return strBuilder.toString();
}
public static Set<String> getNeedSignedHeaderSet() {
return needSignedHeaderSet;
}
public static void setNeedSignedHeaderSet(Set<String> needSignedHeaderSet) {
COSSigner.needSignedHeaderSet = needSignedHeaderSet;
}
public void setCIWorkflowRequest(Boolean CIRequest) {
isCIWorkflowRequest = CIRequest;
}
public int getLocalTimeDelta() {
return localTimeDelta;
}
public void setLocalTimeDelta(int localTimeDelta) {
this.localTimeDelta = localTimeDelta;
}
}
3.生成预上传url 和 生成预下载限速 url
第一步生成临时密钥后获取临时密钥id,key,token参数用来创建实例
创建好后生成预上传url 代码如下
package com.qpyx.oss.utils;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.Headers;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.BasicSessionCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.http.HttpMethodName;
import com.qcloud.cos.http.HttpProtocol;
import com.qcloud.cos.model.*;
import com.qcloud.cos.region.Region;
import com.tencent.cloud.Response;
import java.net.URL;
import java.util.Date;
/**
* 合同存储云策略
*/
public class ContractCloudStorage {
// 创建 COSClient 实例,这个实例用来后续调用请求
static COSClient createCOSClient() {
// 这里需要已经获取到临时密钥的结果。
Response temporarySecretKey = TemporarySecretKey.getTemporarySecretKey();
String tmpSecretId = temporarySecretKey.credentials.tmpSecretId;
String tmpSecretKey = temporarySecretKey.credentials.tmpSecretKey;
String sessionToken = temporarySecretKey.credentials.sessionToken;
COSCredentials cred = new BasicSessionCredentials(tmpSecretId, tmpSecretKey, sessionToken);
// ClientConfig 中包含了后续请求 COS 的客户端设置:
ClientConfig clientConfig = new ClientConfig();
// 设置 bucket 的地域
clientConfig.setRegion(new Region("ap-guangzhou"));
// 设置请求协议, http 或者 https
// 5.6.53 及更低的版本,建议设置使用 https 协议
// 5.6.54 及更高版本,默认使用了 https
clientConfig.setHttpProtocol(HttpProtocol.https);
// 以下的设置,是可选的:
// 设置 socket 读取超时,默认 30s
clientConfig.setSocketTimeout(30*1000);
// 设置建立连接超时,默认 30s
clientConfig.setConnectionTimeout(30*1000);
// 如果需要的话,设置 http 代理,ip 以及 port
clientConfig.setHttpProxyIp("httpProxyIp");
clientConfig.setHttpProxyPort(80);
// 生成 cos 客户端。
return new COSClient(cred, clientConfig);
}
/**
* 生成预下载 限速
* */
public static String GenerateSimplePreSignedDownloadUrl(String key) {
// 1 初始化用户身份信息(secretId, secretKey) 这里填你自己的
COSCredentials cred = new BasicCOSCredentials("secretId", "secretKey");
// 2 设置bucket的区域, COS地域的简称请参照官方文档
ClientConfig clientConfig = new ClientConfig(new Region("ap-guangzhou"));
// 如果要获取 https 的 url 则在此设置,否则默认获取的是 http url
clientConfig.setHttpProtocol(HttpProtocol.https);
// 3 生成cos客户端
COSClient cosclient = new COSClient(cred, clientConfig);
// bucket名需包含appid 这里填自己的桶名
String bucketName = "bucketName";
GeneratePresignedUrlRequest req =
new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
// 设置签名过期时间(可选), 若未进行设置则默认使用ClientConfig中的签名过期时间(30分钟)
// 这里设置签名在一分钟后过期
Date expirationDate = new Date(System.currentTimeMillis() + 60 * 1000);
req.setExpiration(expirationDate);
// 填写本次请求的参数
// 设定限速值,这里限速10M/s
req.addRequestParameter("x-cos-traffic-limit", "8388608");
// 填写本次请求的头部。Host 必填
req.putCustomRequestHeader(Headers.HOST,
cosclient.getClientConfig().getEndpointBuilder().buildGeneralApiEndpoint(bucketName));
//req.putCustomRequestHeader("header1", "value1");
URL url = cosclient.generatePresignedUrl(req);
cosclient.shutdown();
return url.toString();
}
/**
* 生成预签名 + 生成预下载覆盖头部
* */
public static Map<String,String> generatePreSignedUrl(String bucketName, String key, HttpMethodName method) throws CosClientException{
// 调用 COS 接口之前必须保证本进程存在一个 COSClient 实例,如果没有则创建
COSClient cosClient = createCOSClient();
// 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
// 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
// 设置签名过期时间(可选), 若未进行设置则默认使用 ClientConfig 中的签名过期时间(5分钟)
// 这里设置签名在半个小时后过期
Date expirationDate = new Date(System.currentTimeMillis() + 60 * 5000);
// 填写本次请求的参数,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的参数 没有不填之
Map<String, String> params = new HashMap<String, String>();
// 填写本次请求的头部,需与实际请求相同,能够防止用户篡改此签名的 HTTP 请求的头部 没有不填之
Map<String, String> headers = new HashMap<String, String>();
// 请求的 HTTP 方法,上传请求用 PUT,下载请求用 GET,删除请求用 DELETE
URL url = cosClient.generatePresignedUrl(bucketName, key, expirationDate, method, headers, params);
GeneratePresignedUrlRequest req =
new GeneratePresignedUrlRequest(bucketName, key, HttpMethodName.GET);
// 确认本进程不再使用 cosClient 实例之后,关闭之
cosClient.shutdown();
String generatePreSignedUrl = generatePreSignedUrl(req);
Map<String, String> result = new HashMap<String, String>();
result.put("url",url.toString());
result.put("resultUrl",generatePreSignedUrl);
return result;
}
/**
* 生成预下载覆盖头部
* */
public static String generatePreSignedUrl(GeneratePresignedUrlRequest req) throws CosClientException{
COSClient cosClient = createCOSClient();
// 设置下载时返回的 http 头
ResponseHeaderOverrides responseHeaders = new ResponseHeaderOverrides();
String responseContentType = req.getContentType();
String responseContentLanguage = "zh-CN";
// 设置返回头部里包含文件名信息
String responseContentDispositon = "filename=\""+req.getKey()+"\"";
String responseCacheControl = "no-cache";
String cacheExpireStr =
DateUtils.formatRFC822Date(new Date(System.currentTimeMillis() + 24L * 3600L * 1000L));
responseHeaders.setContentType(responseContentType);
responseHeaders.setContentLanguage(responseContentLanguage);
responseHeaders.setContentDisposition(responseContentDispositon);
responseHeaders.setCacheControl(responseCacheControl);
responseHeaders.setExpires(cacheExpireStr);
req.setResponseHeaders(responseHeaders);
// 设置签名过期时间(可选),若未进行设置,则默认使用 ClientConfig 中的签名过期时间(1分钟)
// 这里设置签名在半个小时后过期
Date expirationDate = new Date(System.currentTimeMillis() + 60L * 1000L);
req.setExpiration(expirationDate);
// 填写本次请求的头部
// host 必填
req.putCustomRequestHeader(Headers.HOST, cosClient.getClientConfig().getEndpointBuilder().buildGeneralApiEndpoint(req.getBucketName()));
URL url = cosClient.generatePresignedUrl(req);
System.out.println(url.toString());
// 确认本进程不再使用 cosClient 实例之后,关闭之
cosClient.shutdown();
return url.toString();
}
/**
* 生成签名 URL
* */
public static String getSignature() throws CosClientException{
// 这里需要已经获取到临时密钥的结果。
Response temporarySecretKey = TemporarySecretKey.getTemporarySecretKey();
String tmpSecretId = temporarySecretKey.credentials.tmpSecretId;
String tmpSecretKey = temporarySecretKey.credentials.tmpSecretKey;
String sessionToken = temporarySecretKey.credentials.sessionToken;
COSCredentials cred = new BasicSessionCredentials(tmpSecretId, tmpSecretKey, sessionToken);
// 存储桶的命名格式为 BucketName-APPID,此处填写的存储桶名称必须为此格式
String bucketName = "qipa-contract-***3";
// 对象键(Key)是对象在存储桶中的唯一标识。详情请参见 [对象键](https://cloud.tencent.com/document/product/436/13324)
String key = "contractExampleObject";
//若key不是以“/”开头,则需要在key的开头加上“/”,否则直接resource_path=key
String resource_path="/" + key;
ClientConfig clientConfig = new ClientConfig(new Region("ap-guangzhou"));
// 用来生成签名
COSSigner signer = new COSSigner();
// 设置签名过期时间(可选),若未进行设置,则默认使用 ClientConfig 中的签名过期时间(5分钟)
// 这里设置签名在半个小时后过期
Date expirationDate = new Date(System.currentTimeMillis() + 60L * 5000L);
// 填写本次请求的参数
Map<String, String> params = new HashMap<String, String>();
params.put("param1", "value1");
// 填写本次请求的头部
Map<String, String> headers = new HashMap<String, String>();
// host 必填
headers.put(Headers.HOST, clientConfig.getEndpointBuilder().buildGeneralApiEndpoint(bucketName));
headers.put("header1", "value1");
// 请求的 HTTP 方法,上传请求用 PUT,下载请求用 GET,删除请求用 DELETE
HttpMethodName method = HttpMethodName.GET;
String sign = signer.buildAuthorizationStr(method, resource_path, headers, params, cred, expirationDate, true);
return sign;
}
}
4.生成上传url后可通过url上传文件到桶内!注意上传为put请求
/**
* 上传图片
* @param file
* @return
*/
@Override
public boolean upload(Integer id,MultipartFile file) {
String originalfileName = file.getOriginalFilename();
String[] split = originalfileName.split("\\.");
//防止名称重复随机生成序列号
String path = getPath(split[1]);
//这里调用之前封装的接口 第二个参数为上传桶内的路径+文件名 签名放行了a*的所有路径所有a开头文件夹按年月分层级上传 注意文件名要带文件类型后缀例如aa.jpg 等
Map<String, String> signMap = ContractCloudStorage.generatePreSignedUrl("自己的桶名", "a/"+ path, HttpMethodName.PUT);
String url = signMap.get("url");
//这里的k 可以入库存起来 因为后续下载需要用到 根据k生成临时的下载链接
String key = "contract/"+ path;
try {
upLoadFileByFile(url, file);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
*
* 根据临时签名 上传文件
* */
public static int upLoadFileByFile(String singnedurl,MultipartFile file) throws Exception{
URL url=new URL(singnedurl);
InputStream inputStream = file.getInputStream();
int responseCode = 0;
try {
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
DataOutputStream out = new DataOutputStream(connection.getOutputStream());
//out=new OutputStreamWriter(new FileOutputStream(new File("c:/qqq.zip")));
// 写入要上传的数据
byte buff[]= new byte[1024];
int len;
while( (len=inputStream.read(buff))!=-1 ) {
out.write(buff, 0, len);
}
out.close();
responseCode = connection.getResponseCode();
log.info("Service returned response code " + responseCode);
} catch (ProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return responseCode;
}
//生成路径
public String getPath(String suffix) {
//获取年月
String time = DateUtil.format(DateUtil.date(), "yyyyMM");
// 生成uuid
String uuid = IdUtil.fastSimpleUUID();
// 文件路径
String path = time + "/" + uuid;
return path + "."+suffix;
}
5.文件下载
文件下载统一用get请求这里调用上面封装的方法
/**
* 获取合同下载地址
*
* @param key 对象key 这里的k就是上传时候的文件路径
* @return url
*/
@Override
public AjaxResult download(String key) {
String url = ContractCloudStorage.GenerateSimplePreSignedDownloadUrl(key);
return AjaxResult.success("操作成功",url);
}
整个上传下载流程就完成啦!这里生成的url地址有效期都是一分钟因为前面有设置,每次要获取下载地址需要根据桶内对象k调用下载接口生成下载ur地址,过期自动失效非常安全!!。
不懂得可以留言。