目錄
1、準備配置
任何一個東西,都是從0到1的過程,解決問題之前,我們得先有一個賬號(已有賬號可以跳過此步驟)
- 首先,我們準備一個騰訊雲(https://cloud.tencent.com/)的賬號(沒有就註冊一個),然後首頁選擇對象存儲,點擊立即使用跳轉;
- 然後登錄進來後看到這個,可以免費使用6個月,還是感覺不錯的,雖然買一般的也不貴,但是有便宜不佔是孫子,哈哈
- 現在我們就可以來創建一個存儲桶了,這裏注意訪問權限選擇公有讀寫,不然圖片上傳成功後無法預覽
- 創建成功後,點擊列表的存儲桶名稱或配置管理,就可以查看桶的一些配置,比如可以新建個文件存放圖片啥的。然後我們再選擇密鑰管理,新建一個密鑰(APPID),SecretId、SecretKey用於代碼裏面的配置。
廢話不多說,上代碼
public class QCloudUtil {
public static ResponseVo writeFile(CloudStorageConfigVo cloudStorageConfig, String filePath, MultipartFile file) {
String accessKey = cloudStorageConfig.getQcloudSecretId();
String secretKey = cloudStorageConfig.getQcloudSecretKey();
String bucket = cloudStorageConfig.getQcloudRegion();
// bucket的命名規則爲{name}-{appid} ,此處填寫的存儲桶名稱必須爲此格式
String bucketName = cloudStorageConfig.getQcloudBucketName();
// 1 初始化用戶身份信息(secretId, secretKey)
COSCredentials cred = new BasicCOSCredentials(accessKey, secretKey);
// 2 設置bucket的區域, COS地域的簡稱請參照 https://cloud.tencent.com/document/product/436/6224
ClientConfig clientConfig = new ClientConfig(new Region(bucket));
// 3 生成cos客戶端
COSClient cosclient = new COSClient(cred, clientConfig);
// 簡單文件上傳, 最大支持 5 GB, 適用於小文件上傳, 建議 20 M 以下的文件使用該接口
// 大文件上傳請參照 API 文檔高級 API 上傳
File localFile = null;
try {
localFile = File.createTempFile("temp",null);
file.transferTo(localFile);
// 指定要上傳到 COS 上的路徑
String key = filePath;
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, key, localFile);
PutObjectResult putObjectResult = cosclient.putObject(putObjectRequest);
return new ResponseVo(CoreConst.SUCCESS_CODE,"上傳成功");
} catch (IOException e) {
return new ResponseVo(CoreConst.FAIL_CODE,e.getMessage());
}finally {
// 關閉客戶端(關閉後臺線程)
cosclient.shutdown();
}
}
}
- 雲配置類
/**
* 雲存儲配置信息
*/
public class CloudStorageConfigVo {
//類型 1:七牛 2:阿里雲 3:騰訊雲
private Integer type;
//七牛綁定的域名
private String qiniuDomain="";
//七牛路徑前綴
private String qiniuPrefix="";
//七牛ACCESS_KEY
private String qiniuAccessKey="";
//七牛SECRET_KEY
private String qiniuSecretKey="";
//七牛存儲空間名
private String qiniuBucketName="";
//阿里雲綁定的域名
private String aliyunDomain="";
//阿里雲路徑前綴
private String aliyunPrefix="";
//阿里雲EndPoint
private String aliyunEndPoint="";
//阿里雲AccessKeyId
private String aliyunAccessKeyId="";
//阿里雲AccessKeySecret
private String aliyunAccessKeySecret="";
//阿里雲BucketName
private String aliyunBucketName="";
//騰訊雲綁定的域名
private String qcloudDomain="";
//騰訊雲路徑前綴
private String qcloudPrefix="";
//騰訊雲AppId
private Integer qcloudAppId;
//騰訊雲SecretId
private String qcloudSecretId="";
//騰訊雲SecretKey
private String qcloudSecretKey="";
//騰訊雲BucketName
private String qcloudBucketName="";
//騰訊雲COS所屬地區
private String qcloudRegion="";
}
- 上傳圖片代碼*(Java已經實現了MD5、SHA1算法。利用java.security.MessageDigest類就可以獲取字符串和文件的MD5以及SHA1結果)
//騰訊雲對象存儲
@ResponseBody
@PostMapping(value = "/upload")
public UploadResponse upload(@RequestParam(value = "file", required = false) MultipartFile file) throws Exception {
if(file == null || file.isEmpty()) {
throw new UploadFileNotFoundException(UploadResponse.Error.FILENOTFOUND);
}
try {
String originalFileName = file.getOriginalFilename();
String suffix = originalFileName.substring(originalFileName.lastIndexOf(".")).toLowerCase();
// 數據庫查詢雲配置
String value = sysConfigService.selectAll().get(SysConfigKey.CLOUD_STORAGE_CONFIG.getValue());
Gson gson = new Gson();
// 轉換爲一個配置對象
CloudStorageConfigVo cloudStorageConfig = gson.fromJson(value, CloudStorageConfigVo.class);
//獲取騰訊雲路徑前綴
String dir = cloudStorageConfig.getQcloudPrefix();
// 獲取字符串的MD5結果,file.getBytes()--輸入的字符串轉換成字節數組
String md5 = MD5.getMessageDigest(file.getBytes());
String filePath = String.format("%1$s/%2$s%3$s", dir, md5, suffix);
ResponseVo responseVo = QCloudUtil.writeFile(cloudStorageConfig, filePath, file);
String qCloudDomain = cloudStorageConfig.getQcloudDomain();
String url = String.format("%1$s/%2$s", qCloudDomain, filePath);
if(responseVo.getStatus().equals(CoreConst.SUCCESS_CODE)){
return new UploadResponse(url,originalFileName, suffix, url, CoreConst.SUCCESS_CODE);
}else{
return new UploadResponse(originalFileName, CoreConst.FAIL_CODE,responseVo.getMsg());
}
} catch (Exception e) {
logger.error(String.format("UploadController.upload%s", e));
throw e;
}
}
-
MD5
-
(Java中的 << 、<<、 >>>表示:)
- << 表示左移,不分正負數,低位補0
- >> 表示右移,如果該數爲正,則高位補0,若爲負數,則高位補1
- >>> 表示無符號右移,也叫邏輯右移,即若該數爲正,則高位補0,而若該數爲負數,則右移後高位同樣補0
public class MD5 {
private MD5() {
}
public final static String getMessageDigest(byte[] buffer) {
//首先初始化一個字符數組,用來存放每個16進制字符
char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
try {
// 拿到一個MD5轉換器(如果想要SHA1參數換成"SHA1")
MessageDigest mdTemp = MessageDigest.getInstance ("MD5");
// buffer 是輸入字符串轉換得到的字節數組
mdTemp.update (buffer);
// 轉換並返回結果,也是字節數組,包含16個元素
byte[] md = mdTemp.digest ();
int j = md.length;
// new一個字符數組,這個就是用來組成結果字符串的(解釋一下:一個byte是八位二進制,也就是2位十六進制字符(2的8次方等於16的2次方))
char str[] = new char[j * 2];
int k = 0;
//遍歷字節數組,通過位運算(位運算效率高),轉換成字符放到字符數組中去
for (int i = 0; i < j; i++) {
byte byte0 = md[i];
str[k++] = hexDigits[byte0 >>> 4 & 0xf];
str[k++] = hexDigits[byte0 & 0xf];
}
//字符數組轉換成字符串返回
return new String (str);
} catch (Exception e) {
return null;
}
}
public static String hex(byte[] array) {
StringBuffer sb = new StringBuffer ();
for (int i = 0; i < array.length; ++i) {
sb.append (Integer.toHexString ((array[i]
& 0xFF) | 0x100).substring (1, 3));
}
return sb.toString ();
}
public static String md5Hex(String message) {
try {
MessageDigest md =
MessageDigest.getInstance ("MD5");
return hex (md.digest (message.getBytes ("CP1252")));
} catch (NoSuchAlgorithmException e) {
} catch (UnsupportedEncodingException e) {
}
return null;
}
}
2、解決問題
- 重現問題,上傳圖片的時候提示上傳失敗,顯示異常信息
com.qcloud.cos.exception.CosClientException:
please make sure bucket name must contain legal appid when appid is missing. example: music-1251122334
這個是什麼意思,就是說我們的桶名稱不符合,爲什麼呢,我們查看一下 COSClient類 的源碼,我們直接通過快捷鍵搜索一下 報錯信息中的 music-1251122334,找到這麼一個方法,
// 格式化bucket, 是bucket返回帶appid
private String formatBucket(String bucketName, String appid) throws CosClientException {
String parrtern;
if (appid == null) {
// 正則表達式匹配
parrtern = ".*-(125|100)[0-9]{3,}$";
if (Pattern.matches(parrtern, bucketName)) {
return bucketName;
} else {
throw new CosClientException("please make sure bucket name must contain legal appid when appid is missing. example: music-1251122334");
}
} else {
parrtern = "-" + appid;
return bucketName.endsWith(parrtern) ? bucketName : bucketName + parrtern;
}
}
Pattern與Matcher一起合作.Matcher類提供了對正則表達式的分組支持,以及對正則表達式的多次匹配支持. 單獨用Pattern只能使用Pattern.matches(String regex,CharSequence input)一種最基礎最簡單的匹配。
- 報異常的原因那就是我們的bucketName沒有跟提供的規則匹配上,那規則是什麼呢,就是這句,只匹配了125、100開頭,但是我們的是130開頭的,比如我的:wxb-1301890880
String parrtern = ".*-(125|100)[0-9]{3,}$";
解決的辦法就是更新依賴包,之前使用的是5.2.4版本,現在替換爲5.6.8版本。
<!--騰訊雲存儲依賴-->
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.8</version>
</dependency>