Browse Source

添加腾讯对象存储的实现

Menethil 7 years ago
parent
commit
f24cd5342c

+ 7 - 0
litemall-os-api/pom.xml

@@ -22,6 +22,13 @@
             <artifactId>litemall-db</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos_api</artifactId>
+            <version>5.4.4</version>
+        </dependency>
+
+
     </dependencies>
 
     <build>

+ 26 - 13
litemall-os-api/src/main/java/org/linlinjava/litemall/os/service/FileSystemStorageService.java

@@ -7,14 +7,23 @@ import java.net.MalformedURLException;
 import java.nio.file.*;
 import java.util.stream.Stream;
 
+import org.linlinjava.litemall.os.config.ObjectStorageConfig;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.Resource;
 import org.springframework.core.io.UrlResource;
 import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
 
-@Service
+/**
+ * 服务器本地文件存储
+ */
+@Service("localStorage")
 public class FileSystemStorageService implements StorageService {
 
+    @Autowired
+    private ObjectStorageConfig osConfig;
     private static final Path rootLocation = Paths.get("storage");
+
     static {
         try {
             Files.createDirectories(rootLocation);
@@ -24,12 +33,11 @@ public class FileSystemStorageService implements StorageService {
     }
 
     @Override
-    public void store(InputStream inputStream, String filename) {
+    public void store(MultipartFile file, String keyName) {
         try {
-            Files.copy(inputStream, this.rootLocation.resolve(filename), StandardCopyOption.REPLACE_EXISTING);
-        }
-        catch (IOException e) {
-            throw new RuntimeException ("Failed to store file " + filename, e);
+            Files.copy(file.getInputStream(), this.rootLocation.resolve(keyName), StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to store file " + keyName, e);
         }
     }
 
@@ -39,9 +47,8 @@ public class FileSystemStorageService implements StorageService {
             return Files.walk(this.rootLocation, 1)
                     .filter(path -> !path.equals(this.rootLocation))
                     .map(path -> this.rootLocation.relativize(path));
-        }
-        catch (IOException e) {
-            throw new RuntimeException ("Failed to read stored files", e);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to read stored files", e);
         }
 
     }
@@ -58,12 +65,10 @@ public class FileSystemStorageService implements StorageService {
             Resource resource = new UrlResource(file.toUri());
             if (resource.exists() || resource.isReadable()) {
                 return resource;
-            }
-            else {
+            } else {
                 return null;
             }
-        }
-        catch (MalformedURLException e) {
+        } catch (MalformedURLException e) {
             e.printStackTrace();
             return null;
         }
@@ -79,4 +84,12 @@ public class FileSystemStorageService implements StorageService {
         }
     }
 
+    @Override
+    public String generateUrl(String keyName) {
+        String url = osConfig.getAddress() + ":" + osConfig.getPort() + "/os/storage/fetch/" + keyName;
+        if (!url.startsWith("http")) {
+            url = "http://" + url;
+        }
+        return url;
+    }
 }

+ 16 - 4
litemall-os-api/src/main/java/org/linlinjava/litemall/os/service/StorageService.java

@@ -1,19 +1,31 @@
 package org.linlinjava.litemall.os.service;
 
 import org.springframework.core.io.Resource;
+import org.springframework.web.multipart.MultipartFile;
+
 import java.io.InputStream;
 import java.nio.file.Path;
 import java.util.stream.Stream;
 
+/**
+ * 对象存储接口
+ */
 public interface StorageService {
 
-    void store(InputStream inputStream, String filename);
+    /**
+     * 存储一个文件对象
+     * @param file      SpringBoot MultipartFile文件对象
+     * @param keyName   文件索引名
+     */
+    void store(MultipartFile file, String keyName);
 
     Stream<Path> loadAll();
 
-    Path load(String filename);
+    Path load(String keyName);
+
+    Resource loadAsResource(String keyName);
 
-    Resource loadAsResource(String filename);
+    void delete(String keyName);
 
-    void delete(String filename);
+    String generateUrl(String keyName);
 }

+ 118 - 0
litemall-os-api/src/main/java/org/linlinjava/litemall/os/tencent/TencentOSService.java

@@ -0,0 +1,118 @@
+package org.linlinjava.litemall.os.tencent;
+
+import com.qcloud.cos.COSClient;
+import com.qcloud.cos.ClientConfig;
+import com.qcloud.cos.auth.BasicCOSCredentials;
+import com.qcloud.cos.auth.COSCredentials;
+import com.qcloud.cos.model.ObjectMetadata;
+import com.qcloud.cos.model.PutObjectRequest;
+import com.qcloud.cos.model.PutObjectResult;
+import com.qcloud.cos.region.Region;
+import org.linlinjava.litemall.os.service.StorageService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+
+/**
+ * 腾讯对象存储服务类
+ */
+@PropertySource(value = "classpath:tencent.properties")
+@Service("tencent")
+public class TencentOSService implements StorageService {
+
+    @Value("${tencent.os.secretId}")
+    private String accessKey;
+    @Value("${tencent.os.secretKey}")
+    private String secretKey;
+    @Value("${tencent.os.region}")
+    private String region;
+    @Value("${tencent.os.bucketName}")
+    private String bucketName;
+
+    private COSClient cosClient;
+
+    public TencentOSService() {
+
+    }
+
+    private COSClient getCOSClient() {
+        if (cosClient == null) {
+            // 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(region));
+            cosClient = new COSClient(cred, clientConfig);
+        }
+
+        return cosClient;
+    }
+
+    private String getBaseUrl() {
+        //https://litemall-1256968571.cos-website.ap-guangzhou.myqcloud.com
+        return "https://" + bucketName + ".cos-website." + region + ".myqcloud.com/";
+    }
+
+    @Override
+    public void store(MultipartFile file, String keyName) {
+        try {
+            // 简单文件上传, 最大支持 5 GB, 适用于小文件上传, 建议 20M以下的文件使用该接口
+            ObjectMetadata objectMetadata = new ObjectMetadata();
+            objectMetadata.setContentLength(file.getSize());
+            objectMetadata.setContentType(file.getContentType());
+            // 对象键(Key)是对象在存储桶中的唯一标识。例如,在对象的访问域名 `bucket1-1250000000.cos.ap-guangzhou.myqcloud.com/doc1/pic1.jpg` 中,对象键为 doc1/pic1.jpg, 详情参考 [对象键](https://cloud.tencent.com/document/product/436/13324)
+            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, file.getInputStream(), objectMetadata);
+            PutObjectResult putObjectResult = getCOSClient().putObject(putObjectRequest);
+        } catch (Exception ex) {
+            System.console().printf(ex.getMessage());
+        }
+    }
+
+    @Override
+    public Stream<Path> loadAll() {
+        return null;
+    }
+
+    @Override
+    public Path load(String keyName) {
+        return null;
+    }
+
+    @Override
+    public Resource loadAsResource(String keyName) {
+        try {
+            URL url = new URL(getBaseUrl() + keyName);
+            Resource resource = new UrlResource(url);
+            if (resource.exists() || resource.isReadable()) {
+                return resource;
+            } else {
+                return null;
+            }
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @Override
+    public void delete(String keyName) {
+        try {
+            getCOSClient().deleteObject(bucketName, keyName);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
+    }
+
+    @Override
+    public String generateUrl(String keyName) {
+        return getBaseUrl() + keyName;
+    }
+}

+ 3 - 15
litemall-os-api/src/main/java/org/linlinjava/litemall/os/web/OsStorageController.java

@@ -5,7 +5,6 @@ import org.linlinjava.litemall.core.util.ResponseUtil;
 import org.linlinjava.litemall.db.domain.LitemallStorage;
 import org.linlinjava.litemall.db.service.LitemallStorageService;
 import org.linlinjava.litemall.os.service.StorageService;
-import org.linlinjava.litemall.os.config.ObjectStorageConfig;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.core.io.Resource;
 import org.springframework.http.HttpHeaders;
@@ -25,22 +24,11 @@ import java.util.Map;
 @RequestMapping("/os/storage")
 public class OsStorageController {
 
-    @Autowired
+    @javax.annotation.Resource(name="${activeStorage}")
     private StorageService storageService;
     @Autowired
     private LitemallStorageService litemallStorageService;
 
-    @Autowired
-    private ObjectStorageConfig osConfig;
-
-    private String generateUrl(String key){
-        String url = osConfig.getAddress() + ":" + osConfig.getPort() + "/os/storage/fetch/" + key;
-        if(!url.startsWith("http")){
-            url = "http://" + url;
-        }
-        return url;
-    }
-
     private String generateKey(String originalFilename){
         int index = originalFilename.lastIndexOf('.');
         String suffix = originalFilename.substring(index);
@@ -82,9 +70,9 @@ public class OsStorageController {
             return ResponseUtil.badArgumentValue();
         }
         String key = generateKey(originalFilename);
-        storageService.store(inputStream, key);
+        storageService.store(file, key);
 
-        String url = generateUrl(key);
+        String url = storageService.generateUrl(key);
         LitemallStorage storageInfo = new LitemallStorage();
         storageInfo.setName(originalFilename);
         storageInfo.setSize((int)file.getSize());

+ 5 - 0
litemall-os-api/src/main/resources/application.properties

@@ -1,3 +1,8 @@
 spring.profiles.active=dev
 server.port=8081
 logging.level.org.linlinjava.litemall.os.Application=DEBUG
+
+
+# \u5B58\u50A8\u5B9E\u73B0\uFF0C\u53EF\u9009\u62E9 localStorage \u6216\u8005 tencent \uFF0C\u5982\u679C\u9009\u62E9 tencent\uFF0C\u9700\u8981\u5F00\u901A\u817E\u8BAF\u5BF9\u8C61\u5B58\u50A8\u5E76\u914D\u7F6E tencent.properties
+activeStorage=localStorage
+#activeStorage=tencent

+ 6 - 0
litemall-os-api/src/main/resources/tencent.properties

@@ -0,0 +1,6 @@
+
+# \u817E\u8BAF\u4E91\u5B58\u50A8\u76F8\u5173\u914D\u7F6E,\u817E\u8BAF\u4E91\u5FC5\u987B\u6253\u5F00 #\u9759\u6001\u7F51\u7AD9(https://cloud.tencent.com/document/product/436/6249) \u652F\u6301\uFF0C\u5426\u5219\u56FE\u7247\u4F1A\u76F4\u63A5\u4E0B\u8F7D\u800C\u4E0D\u662F\u663E\u793A
+tencent.os.secretId=""
+tencent.os.secretKey=""
+tencent.os.region=""
+tencent.os.bucketName=""