Java项目接入阿里云OSS存储

时间:2021-02-15 09:16:20

需求背景

目前公司内部项目所支持的文件云存储方式还是公司内部项目组提供的方案,但在时间的考验之下,弊端显现,尤其是灾备切换过程中需要切换访问地址,这种操作不方便,更可能因为中间过程的失误导致资源不可用,而且这种操作也会带来资源可用的延时,仔细斟酌发现这种操作似乎并不合逻辑。

在众多项目组的千呼万唤之下,阿里云的OSS存储方案进入了我们的视线,依托公共云环境,屏蔽项目本身切换状态可能带来的资源不可用的问题,将资源存储与访问独立出来,极大的与企业自有项目解耦,同时降低企业自身项目运行状态对公共资源访问的影响。

项目接入

Captain的本项目基于JDK1.8,采用SpringBoot框架开发。

前期准备

从阿里云平台获取到endpoint、accessKeyId、accessKeySecret相关配置信息,因为只有在这些信息的支持下,才能展开后续功能的开发。

创建bucket(存储命名空间、平台唯一才行),可以在阿里云操作台建立,也可以通过代码生成。

Maven依赖

1 <dependency>
2     <groupId>com.aliyun.oss</groupId>
3     <artifactId>aliyun-sdk-oss</artifactId>
4     <version>2.8.3</version>
5 </dependency>

属性配置

可以将和环境相关的固定配置类信息放置于properties文件中:

# aliyun oss
aliyun.oss.endpoint="http://oss-cn-hangzhou.aliyuncs.com"
aliyun.oss.keyid=<yourAccessKeyId>
aliyun.oss.keysecret=<yourAccessKeySecret>
aliyun.oss.bucketname=<yourBucketName>

# aliyun filehost based on dev/test/prod(tha/idn)
aliyun.oss.filehost=dev

编写工具类

  1 /**
  2  * @Project: captain-supply-chain
  3  * @PackageName: com.captain.supply-chain.common.file
  4  * @Author: Captain&D
  5  * @cnblogs: https://www.cnblogs.com/captainad
  6  * @DateTime: 2019/5/10 18:12.
  7  * @Description: Upload file to Aliyun OSS.
  8  */
  9 @Slf4j
 10 @Component
 11 public class AliyunOssService {
 12 
 13     /**
 14      * 斜杠
 15      */
 16     private final String FLAG_SLANTING_ROD = "/";
 17     /**
 18      * http://
 19      */
 20     private final String FLAG_HTTP = "http://";
 21     /**
 22      * https://
 23      */
 24     private final String FLAG_HTTPS = "https://";
 25     /**
 26      * 空字符串
 27      */
 28     private final String FLAG_EMPTY_STRING = "";
 29     /**
 30      * 点号
 31      */
 32     private final String FLAG_DOT = ".";
 33     /**
 34      * 横杠
 35      */
 36     private final String FLAG_CROSSBAR = "-";
 37 
 38     /**
 39      * 缺省的最大上传文件大小:20M
 40      */
 41     private final int DEFAULT_MAXIMUM_FILE_SIZE = 20;
 42 
 43     /**
 44      * endpoint
 45      */
 46     @Value("${aliyun.oss.endpoint}")
 47     private String endpoint;
 48 
 49     /**
 50      * access key id
 51      */
 52     @Value("${aliyun.oss.keyid}")
 53     private String accessKeyId;
 54 
 55     /**
 56      * access key secret
 57      */
 58     @Value("${aliyun.oss.keysecret}")
 59     private String accessKeySecret;
 60 
 61     /**
 62      * bucket name (namespace)
 63      */
 64     @Value("${aliyun.oss.bucketname}")
 65     private String bucketName;
 66 
 67     /**
 68      * file host (dev/test/prod)
 69      */
 70     @Value("${aliyun.oss.filehost}")
 71     private String fileHost;
 72 
 73     @Autowired
 74     protected GetSetCacheService getSetCacheService;
 75 
 76     /**
 77      * 以文件流的方式上传文件
 78      * @Author: Captain&D
 79      * @cnblogs: https://www.cnblogs.com/captainad
 80      * @param fileName 文件名称
 81      * @param filePath 文件路径
 82      * @param inputStream 文件输入流
 83      * @return
 84      */
 85     public String uploadFile(String fileName, String filePath, InputStream inputStream) {
 86         return coreUpload(fileName, filePath, inputStream);
 87     }
 88 
 89     /**
 90      * 核心上传功能
 91      * @Author: Captain&D
 92      * @cnblogs: https://www.cnblogs.com/captainad
 93      * @param fileName 文件名
 94      * @param filePath 文件路径
 95      * @param inputStream 文件输入流
 96      * @return
 97      */
 98     private String coreUpload(String fileName, String filePath, InputStream inputStream) {
 99         log.info("Start to upload file....");
100         if(StringUtils.isEmpty(fileName) || inputStream == null) {
101             log.error("Filename Or inputStream is lack when upload file.");
102             return null;
103         }
104         if(StringUtils.isEmpty(filePath)) {
105             log.warn("File path is lack when upload file but we automatically generated");
106             String dateCategory = DateUtil.getFormatDate(new Date(), "yyyyMMdd");
107             filePath = FLAG_SLANTING_ROD.concat(dateCategory).concat(FLAG_SLANTING_ROD);
108         }
109         String fileUrl;
110         OSSClient ossClient = null;
111         try{
112 
113             // If the upload file size exceeds the limit
114             long maxSizeAllowed = getMaximumFileSizeAllowed();
115             if(Long.valueOf(inputStream.available()) > maxSizeAllowed) {
116                 log.error("Uploaded file is too big.");
117                 return null;
118             }
119 
120             // Create OSS instance
121             ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
122 
123             // Create bucket if not exists
124             if (!ossClient.doesBucketExist(bucketName)) {
125                 log.info("Bucket '{}' is not exists and create it now.", bucketName);
126                 ossClient.createBucket(bucketName);
127                 CreateBucketRequest createBucketRequest = new CreateBucketRequest(bucketName);
128                 createBucketRequest.setCannedACL(CannedAccessControlList.PublicRead);
129                 ossClient.createBucket(createBucketRequest);
130             }
131 
132             /*********************************/
133             // List the bucket in my account
134             //listBuckets(ossClient);
135             /*********************************/
136 
137             // File path format
138             if(!filePath.startsWith(FLAG_SLANTING_ROD)) {
139                 filePath = FLAG_SLANTING_ROD.concat(filePath);
140             }
141             if(!filePath.endsWith(FLAG_SLANTING_ROD)) {
142                 filePath = filePath.concat(FLAG_SLANTING_ROD);
143             }
144 
145             // File url
146             StringBuilder buffer = new StringBuilder();
147             buffer.append(fileHost).append(filePath).append(fileName);
148             fileUrl = buffer.toString();
149             log.info("After format the file url is {}", fileUrl);
150 
151             // Upload file and set ACL
152             PutObjectResult result = ossClient.putObject(new PutObjectRequest(bucketName, fileUrl, inputStream));
153             ossClient.setBucketAcl(bucketName, CannedAccessControlList.PublicRead);
154             if(result != null) {
155                 log.info("Upload result:{}", result.getETag());
156                 log.info("Upload file {} successfully.", fileName);
157             }
158             fileUrl = getHostUrl().concat(fileUrl);
159             log.info("Call path is {}", fileUrl);
160 
161             /***********************************/
162             // List objects in your bucket
163             //listObjects(ossClient);
164             /***********************************/
165 
166         }catch (Exception e){
167             log.error("Upload file failed.", e);
168             fileUrl = null;
169         }finally {
170             if(ossClient != null) {
171                 ossClient.shutdown();
172             }
173         }
174         return fileUrl;
175     }
176 
177     /**
178      * 列出buckets下的所有文件
179      * @Author: Captain&D
180      * @cnblogs: https://www.cnblogs.com/captainad
181      * @param ossClient
182      */
183     private void listObjects(OSSClient ossClient) {
184         System.out.println("Listing objects");
185         ObjectListing objectListing = ossClient.listObjects(bucketName);
186         for (OSSObjectSummary objectSummary : objectListing.getObjectSummaries()) {
187             System.out.println(" - " + objectSummary.getKey() + "  " +
188                     "(size = " + objectSummary.getSize() + ")");
189         }
190         System.out.println();
191     }
192 
193     /**
194      * 列出当前用户下的所有bucket
195      * @Author: Captain&D
196      * @cnblogs: https://www.cnblogs.com/captainad
197      * @param ossClient
198      */
199     private void listBuckets(OSSClient ossClient) {
200         System.out.println("Listing buckets");
201         ListBucketsRequest listBucketsRequest = new ListBucketsRequest();
202         listBucketsRequest.setMaxKeys(500);
203         for (Bucket bucket : ossClient.listBuckets()) {
204             System.out.println(" - " + bucket.getName());
205         }
206         System.out.println();
207     }
208 
209     /**
210      * 以文件的形式上传文件
211      * @Author: Captain&D
212      * @cnblogs: https://www.cnblogs.com/captainad
213      * @param fileName
214      * @param filePath
215      * @param file
216      * @return
217      */
218     public String uploadFile(String fileName, String filePath, File file) {
219         if(file == null) {
220             log.warn("File is lack when upload.");
221             return null;
222         }
223         if(StringUtils.isEmpty(fileName)) {
224             log.warn("File name is lack when upload file but we automatically generated");
225             String uuidFileName = UUID.randomUUID().toString().replace(FLAG_CROSSBAR, FLAG_EMPTY_STRING);
226             String fname = file.getName();
227             String suffix = fname.substring(fname.lastIndexOf(FLAG_DOT), fname.length());
228             fileName = uuidFileName.concat(suffix);
229         }
230         InputStream inputStream = null;
231         String fileUrl = null;
232         try{
233             inputStream = new FileInputStream(file);
234             fileUrl = uploadFile(fileName, filePath, inputStream);
235         }catch (Exception e){
236             log.error("Upload file error.", e);
237         }finally {
238             IOUtils.safeClose(inputStream);
239         }
240         return fileUrl;
241     }
242 
243     /**
244      * 获取访问的base地址
245      * @Author: Captain&D
246      * @cnblogs: https://www.cnblogs.com/captainad
247      * @return
248      */
249     private String getHostUrl() {
250         String hostUrl = null;
251         if(this.endpoint.startsWith(FLAG_HTTP)) {
252             hostUrl = FLAG_HTTP.concat(this.bucketName).concat(FLAG_DOT)
253                     .concat(this.endpoint.replace(FLAG_HTTP, FLAG_EMPTY_STRING)).concat(FLAG_SLANTING_ROD);
254         } else if (this.endpoint.startsWith(FLAG_HTTPS)) {
255             return FLAG_HTTPS.concat(this.bucketName).concat(FLAG_DOT)
256                     .concat(this.endpoint.replace(FLAG_HTTPS, FLAG_EMPTY_STRING)).concat(FLAG_SLANTING_ROD);
257         }
258         return hostUrl;
259     }
260 
261     /**
262      * 获取最大允许上传文件的大小
263      * @Author: Captain&D
264      * @cnblogs: https://www.cnblogs.com/captainad
265      * @return
266      */
267     private long getMaximumFileSizeAllowed() {
268         // 缓存单位是M
269         String maxConfigVal = getSetCacheService.getConfigValue("upload_maximum_file_size");
270         if(StringUtils.isEmpty(maxConfigVal)) {
271             return DEFAULT_MAXIMUM_FILE_SIZE * 1024L * 1024L;
272         }else {
273             return Long.valueOf(maxConfigVal.trim()) * 1024L * 1024L;
274         }
275     }
276 
277     /**
278      * 删除文件
279      * @Author: Captain&D
280      * @cnblogs: https://www.cnblogs.com/captainad
281      * @param fileUrl 文件访问的全路径
282      */
283     public void deleteFile(String fileUrl) {
284         log.info("Start to delete file from OSS.{}", fileUrl);
285         if(StringUtils.isEmpty(fileUrl)
286                 || (!fileUrl.startsWith(FLAG_HTTP)
287                 && !fileUrl.startsWith(FLAG_HTTPS))) {
288             log.error("Delete file failed because the invalid file address. -> {}", fileUrl);
289             return;
290         }
291         OSSClient ossClient = null;
292         try{
293             /**
294              * http:// bucketname                                dev/test/pic/abc.jpg = key
295              * http:// captainad.oss-ap-southeast-1.aliyuncs.com/dev/test/pic/abc.jpg
296              */
297             String key = fileUrl.replace(getHostUrl(), FLAG_EMPTY_STRING);
298             if(log.isDebugEnabled()) {
299                 log.debug("Delete file key is {}", key);
300             }
301             ossClient = new OSSClient(endpoint, accessKeyId, accessKeySecret);
302             ossClient.deleteObject(bucketName, key);
303         }catch (Exception e){
304            log.error("Delete file error.", e);
305         } finally {
306             if(ossClient != null) {
307                 ossClient.shutdown();
308             }
309         }
310     }
311 
312 }

参考资料

1、https://help.aliyun.com/document_detail/32008.html