Springboot 遷移及上傳檔案至阿里雲OSS
本文介紹GitClub小程式後端的伺服器檔案的遷移以及更新圖片上傳至阿里雲OSS儲存伺服器,如果不瞭解GitClub小程式的朋友可以看下我的上篇文章 ofollow,noindex">關於Android開源庫分享平臺,(GitClub)微信小程式的開發體驗 ,在此特別糾正下,當前版本暫時只有Android的開源庫分享,後續會增加Java、iOS、前端等不同語言的分類,感興趣的可以去關注下我們的小程式,原始碼地址: GitClub 。鋪墊結束,請使用掃描這個二維碼登陸GitClub小程式參觀。

一、匯入依賴包,在pox.xml中加入
<dependency> <groupId>com.aliyun.oss</groupId> <artifactId>aliyun-sdk-oss</artifactId> <version>2.8.3</version> </dependency> 複製程式碼
二、配置OSS的引數,建立類OSSConfig
1、新增oss.properties配置檔案,內容如下: #阿里雲OSS配置 #原伺服器地址 bucketUrl = https://bucketName.oss-cn-shenzhen.aliyuncs.com #自定義解析後伺服器地址 baseUrl = https://xxx.502tech.com #可以選擇其他的地址 endpoint = https://oss-cn-qingdao.aliyuncs.com #已經在控制檯建立的bucket bucketName = bucketName #你上傳檔案的儲存路徑,如果bucket中不存在則建立(其實原理並不是資料夾,只是檔名,詳情請先閱讀官方文件) picLocation = GitClub/image/ #相應的id和key值,請填寫你具體的值,這裡不方便展示我自己的。 accessKeyId = 阿里雲OSS的accessKeyId accessKeySecret = 阿里雲OSS的accessKeySecret 2、建立類OSSConfig public class OSSConfig { privateString bucketUrl;//原圖片伺服器地址 privateString baseUrl;//自定義解析後的圖片伺服器地址 privateString endpoint;//連線區域地址 privateString accessKeyId;//連線keyId privateString accessKeySecret;//連線祕鑰 privateString bucketName;//需要儲存的bucketName privateString picLocation;//圖片儲存路徑 public OSSConfig() { try { this.bucketUrl = SystemConfig.getConfigResource("bucketUrl"); this.baseUrl = SystemConfig.getConfigResource("baseUrl"); this.endpoint = SystemConfig.getConfigResource("endpoint"); this.bucketName = SystemConfig.getConfigResource("bucketName"); this.picLocation = SystemConfig.getConfigResource("picLocation"); this.accessKeyId = SystemConfig.getConfigResource("accessKeyId"); this.accessKeySecret = SystemConfig.getConfigResource("accessKeySecret"); } catch (IOException e) { e.printStackTrace(); } } ... 省略get、set方法 複製程式碼
三、建立OSS工具類OSSUploadUtil
private static OSSConfig config = null; /** * * @MethodName: uploadFile * @Description: OSS單檔案上傳 * @param file * @param fileType 檔案字尾 * @return String 檔案地址 */ public static String uploadFile(File file,String fileType){ config = config == null ? new OSSConfig():config; //通過UUID生成檔名 String fileName = config.getPicLocation() +UUID.randomUUID().toString().toUpperCase() .replace("-", "") +"."+fileType; return putFile(file,fileType,fileName); } /** * * @MethodName: updateFile * @Description: 更新檔案:只更新內容,不更新檔名和檔案地址。 * (因為地址沒變,可能存在瀏覽器原資料快取,不能及時載入新資料,例如圖片更新,請注意) * @param file * @param fileType * @param oldUrl * @return String */ public static String updateFile(File file,String fileType,String oldUrl){ String fileName = getFileName(oldUrl); if(fileName==null) return null; return putFile(file,fileType,fileName); } /** * * @MethodName: replaceFile * @Description: 替換檔案:刪除原檔案並上傳新檔案,檔名和地址同時替換 * 解決原資料快取問題,只要更新了地址,就能重新載入資料) * @param file * @param fileType 檔案字尾 * @param oldUrl 需要刪除的檔案地址 * @return String 檔案地址 */ public static String replaceFile(File file,String fileType,String oldUrl){ boolean flag = deleteFile(oldUrl);//先刪除原檔案 if(!flag){ //更改檔案的過期時間,讓他到期自動刪除。 } return uploadFile(file, fileType); } /** * * @MethodName: deleteFile * @Description: 單檔案刪除 * @param fileUrl 需要刪除的檔案url * @return boolean 是否刪除成功 */ public static boolean deleteFile(String fileUrl){ config = config == null ? new OSSConfig():config; String bucketName = OSSUploadUtil.getBucketName(fileUrl);//根據url獲取bucketName String fileName = OSSUploadUtil.getFileName(fileUrl);//根據url獲取fileName if(bucketName==null||fileName==null) return false; OSSClient ossClient = null; try { ossClient = new OSSClient(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret()); GenericRequest request = new DeleteObjectsRequest(bucketName).withKey(fileName); ossClient.deleteObject(request); } catch (Exception oe) { oe.printStackTrace(); return false; } finally { ossClient.shutdown(); } return true; } /** * * @MethodName: batchDeleteFiles * @Description: 批量檔案刪除(較快):適用於相同endPoint和BucketName * @param fileUrls 需要刪除的檔案url集合 * @return int 成功刪除的個數 */ public static int deleteFile(List<String> fileUrls){ int deleteCount = 0;//成功刪除的個數 String bucketName = OSSUploadUtil.getBucketName(fileUrls.get(0));//根據url獲取bucketName List<String> fileNames = OSSUploadUtil.getFileName(fileUrls);//根據url獲取fileName if(bucketName==null||fileNames.size()<=0) return 0; OSSClient ossClient = null; try { ossClient = new OSSClient(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret()); DeleteObjectsRequest request = new DeleteObjectsRequest(bucketName).withKeys(fileNames); DeleteObjectsResult result = ossClient.deleteObjects(request); deleteCount = result.getDeletedObjects().size(); } catch (OSSException oe) { oe.printStackTrace(); throw new RuntimeException("OSS服務異常:", oe); } catch (ClientException ce) { ce.printStackTrace(); throw new RuntimeException("OSS客戶端異常:", ce); } finally { ossClient.shutdown(); } return deleteCount; } /** * * @MethodName: batchDeleteFiles * @Description: 批量檔案刪除(較慢):適用於不同endPoint和BucketName * @param fileUrls 需要刪除的檔案url集合 * @return int 成功刪除的個數 */ public static int deleteFiles(List<String> fileUrls){ int count = 0; for (String url : fileUrls) { if(deleteFile(url)){ count++; } } return count; } /** * * @MethodName: putFile * @Description: 上傳檔案 * @param file * @param fileType * @param fileName * @return String */ private static String putFile(File file, String fileType, String fileName){ config = config==null?new OSSConfig():config; String url = null;//預設null OSSClient ossClient = null; try { ossClient = new OSSClient(config.getEndpoint(), config.getAccessKeyId(), config.getAccessKeySecret()); InputStream input = new FileInputStream(file); ObjectMetadata meta = new ObjectMetadata();// 建立上傳Object的Metadata meta.setContentType(OSSUploadUtil.contentType(fileType));// 設定上傳內容型別 meta.setCacheControl("no-cache");// 被下載時網頁的快取行為 PutObjectRequest request = new PutObjectRequest(config.getBucketName(), fileName,input,meta);//建立上傳請求 ossClient.putObject(request); Date expiration = new Date(new Date().getTime() + 3600L * 1000 * 24 * 365 * 10); // 設定URL過期時間為10年3600L* 1000*24*365*10 //上傳成功再返回的檔案路徑 url = ossClient.generatePresignedUrl(config.getBucketName(), fileName, expiration) .toString() .replaceFirst(config.getBucketUrl(), config.getBaseUrl()); } catch (OSSException | FileNotFoundException | ClientException oe) { oe.printStackTrace(); return null; } finally { if (ossClient != null) { ossClient.shutdown(); } } return url; } /** * * @MethodName: contentType * @Description: 獲取檔案型別 * @param fileType * @return String */ private static String contentType(String fileType){ fileType = fileType.toLowerCase(); String contentType = ""; switch (fileType) { case "bmp":contentType = "image/bmp"; break; case "gif":contentType = "image/gif"; break; case "png": case "jpeg": case "jpg":contentType = "image/jpeg"; break; case "html":contentType = "text/html"; break; case "txt":contentType = "text/plain"; break; case "vsd":contentType = "application/vnd.visio"; break; case "ppt": case "pptx":contentType = "application/vnd.ms-powerpoint"; break; case "doc": case "docx":contentType = "application/msword"; break; case "xml":contentType = "text/xml"; break; case "mp4":contentType = "video/mp4"; break; default: contentType = "application/octet-stream"; break; } return contentType; } /** * * @MethodName: getBucketName * @Description: 根據url獲取bucketName * @param fileUrl 檔案url * @return String bucketName */ private static String getBucketName(String fileUrl){ String http = "http://"; String https = "https://"; int httpIndex = fileUrl.indexOf(http); int httpsIndex = fileUrl.indexOf(https); int startIndex= 0; if(httpIndex==-1){ if(httpsIndex==-1){ return null; }else{ startIndex = httpsIndex+https.length(); } }else{ startIndex = httpIndex+http.length(); } int endIndex = fileUrl.indexOf(".oss-"); return fileUrl.substring(startIndex, endIndex); } /** * * @MethodName: getFileName * @Description: 根據url獲取fileName * @param fileUrl 檔案url * @return String fileName */ private static String getFileName(String fileUrl){ String str = "aliyuncs.com/"; int beginIndex = fileUrl.indexOf(str); if(beginIndex==-1) return null; return fileUrl.substring(beginIndex+str.length()); } /** * * @MethodName: getFileName * @Description: 根據url獲取fileNames集合 * @param fileUrls 檔案url * @return List<String>fileName集合 */ private static List<String> getFileName(List<String> fileUrls){ List<String> names = new ArrayList<>(); for (String url : fileUrls) { names.add(getFileName(url)); } return names; } } 複製程式碼
四、測試
//把之前上傳到專案特定目錄下的邏輯修改成上傳至OSS @PostMapping("/uploadArticleImg") public Result<Map<String, String>> uploadArticleImg(@RequestParam(value = "article_img") MultipartFile file) { if (file == null || file.isEmpty() || file.getSize() == 0) { return ResultUtils.error(ResultCode.UPLOAD_FILE_EMPTY); } if (file.getSize() > 10 * 1024 * 1024) { return ResultUtils.error(ResultCode.UPLOAD_FILE_LIMIT); } Map<String, String> map = new HashMap<>(); String fileType = file.getOriginalFilename().substring(file.getOriginalFilename().lastIndexOf(".")+1); //OSS單檔案上傳,返回上傳成功後的oss儲存伺服器中的url String fileName = OSSUploadUtil.uploadFile(FileUtils.multi2File(file), fileType); map.put(file.getName(), fileName); return ResultUtils.ok(map); } 複製程式碼
五、如何把資料庫中把之前已經上傳的檔案URL更新成OSS返回的URL
@PostMapping("/trasform2OSS") public Result<Boolean> trasformImg2OSS(){ File path = null; try { path = new File(ResourceUtils.getURL("classpath:").getPath()); } catch (FileNotFoundException e) { e.printStackTrace(); } if (!path.exists()) path = new File(""); System.out.println("path:" + path.getAbsolutePath()); //如果上傳目錄為/static/images/upload/,則可以如下獲取: File upload = new File(path.getAbsolutePath(), "static/images/upload/"); if (!upload.exists()) upload.mkdirs(); System.out.println("upload url:" + upload.getAbsolutePath()); File[] files = upload.listFiles(); //更新圖片的url到oss並把最新oss的圖片地址儲存到資料庫 List<Article> articles = articleRepository.findAll(); articles.forEach(article -> { if (null != article){ for (File file : files){ if(null != file){ if(null == article.getImg_url() || null == file.getName()){ continue; } if(article.getImg_url().contains(file.getName())){ //上傳到oss String fileType = file.getName().substring(file.getName().lastIndexOf(".")+1); String url = OSSUploadUtil.uploadFile(file, fileType); logger.info("上傳到oss地址:"+url); //更新到伺服器 article.setImg_url(url); articleRepository.saveAndFlush(article); //更新資料到引擎 articleSearchRepository.save(new ESArticle(article)); } } } } }); return ResultUtils.ok(true); } 複製程式碼
六、阿里雲OSS管理配置的一些坑
因為之前我們的圖片上傳至專案目錄中的指定路徑如: 502tech.com/geekdaily/x… 現在需要全部替換成如: xxx.502tech.com/123.png 格式,注意:這裡xxx.502tech.com是我們的二級域名,上傳檔案至OSS之後預設會返回如: bucketName.oss-cn-shenzhen.aliyuncs.com/123.png 格式。需要我們手動在阿里雲OSS域名管理中去繫結域名,如果想要使用https,則需要申請SSL證書,這裡你可以申請一個免費的,可以自行百度,大概15分鐘會申請成功,然後需要在OSS的域名管理中新增SSL證書,這裡切記:下載nginx版本的證書,然後複製貼上對應的公鑰和私鑰。