ソースを参照

feat[litemall-core]: core模块支持存储,包括本地存储、腾讯云存储、阿里云存储

Junling Bu 7 年 前
コミット
1072fc97bc

+ 1 - 0
litemall-core/.gitignore

@@ -1,3 +1,4 @@
 
 /target/
 /litemall-core.iml
+/storage/

+ 19 - 0
litemall-core/pom.xml

@@ -38,6 +38,25 @@
             <artifactId>qcloudsms</artifactId>
             <version>1.0.5</version>
         </dependency>
+
+        <dependency>
+            <groupId>com.qcloud</groupId>
+            <artifactId>cos_api</artifactId>
+            <version>5.4.4</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>slf4j-log4j12</artifactId>
+                    <groupId>org.slf4j</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <dependency>
+            <groupId>com.aliyun.oss</groupId>
+            <artifactId>aliyun-sdk-oss</artifactId>
+            <version>2.5.0</version>
+        </dependency>
+
         <dependency>
             <groupId>com.github.binarywang</groupId>
             <artifactId>weixin-java-miniapp</artifactId>

+ 132 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/storage/AliyunStorage.java

@@ -0,0 +1,132 @@
+package org.linlinjava.litemall.core.storage;
+
+import com.aliyun.oss.OSSClient;
+import com.aliyun.oss.model.ObjectMetadata;
+import com.aliyun.oss.model.PutObjectRequest;
+import com.aliyun.oss.model.PutObjectResult;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.nio.file.Path;
+import java.util.stream.Stream;
+
+/**
+ * @author Yogeek
+ * @date 2018/7/16 16:10
+ * @decrpt 阿里云对象存储服务
+ */
+public class AliyunStorage implements Storage {
+
+    private  String endpoint;
+    private  String accessKeyId;
+    private  String accessKeySecret;
+    private  String bucketName;
+
+    public String getEndpoint() {
+        return endpoint;
+    }
+
+    public void setEndpoint(String endpoint) {
+        this.endpoint = endpoint;
+    }
+
+    public String getAccessKeyId() {
+        return accessKeyId;
+    }
+
+    public void setAccessKeyId(String accessKeyId) {
+        this.accessKeyId = accessKeyId;
+    }
+
+    public String getAccessKeySecret() {
+        return accessKeySecret;
+    }
+
+    public void setAccessKeySecret(String accessKeySecret) {
+        this.accessKeySecret = accessKeySecret;
+    }
+
+    public String getBucketName() {
+        return bucketName;
+    }
+
+    public void setBucketName(String bucketName) {
+        this.bucketName = bucketName;
+    }
+
+    /**
+     * 获取阿里云OSS客户端对象
+     *
+     * @return ossClient
+     */
+    private OSSClient getOSSClient(){
+        return new OSSClient(endpoint,accessKeyId, accessKeySecret);
+    }
+
+    private String getBaseUrl() {
+        return "https://" + bucketName + "." +  endpoint + "/" ;
+    }
+
+    /**
+     * 阿里云OSS对象存储简单上传实现
+     */
+    @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)是对象在存储桶中的唯一标识。
+            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, keyName, file.getInputStream(), objectMetadata);
+            PutObjectResult putObjectResult = getOSSClient().putObject(putObjectRequest);
+        } catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+    }
+
+    @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 {
+            getOSSClient().deleteObject(bucketName, keyName);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+
+    }
+
+    @Override
+    public String generateUrl(String keyName) {
+        return getBaseUrl() + keyName;
+    }
+}

+ 119 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/storage/LocalStorage.java

@@ -0,0 +1,119 @@
+package org.linlinjava.litemall.core.storage;
+
+
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.stream.Stream;
+
+/**
+ * 服务器本地对象存储服务
+ */
+public class LocalStorage implements Storage {
+
+    private String storagePath;
+    private String address;
+    private String port;
+
+    private Path rootLocation;
+
+    public String getStoragePath() {
+        return storagePath;
+    }
+
+    public void setStoragePath(String storagePath) {
+        this.storagePath = storagePath;
+
+        this.rootLocation = Paths.get(storagePath);
+        try {
+            Files.createDirectories(rootLocation);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getPort() {
+        return port;
+    }
+
+    public void setPort(String port) {
+        this.port = port;
+    }
+
+
+    @Override
+    public void store(MultipartFile file, String keyName) {
+        try {
+            Files.copy(file.getInputStream(), rootLocation.resolve(keyName), StandardCopyOption.REPLACE_EXISTING);
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to store file " + keyName, e);
+        }
+    }
+
+    @Override
+    public Stream<Path> loadAll() {
+        try {
+            return Files.walk(rootLocation, 1)
+                    .filter(path -> !path.equals(rootLocation))
+                    .map(path -> rootLocation.relativize(path));
+        } catch (IOException e) {
+            throw new RuntimeException("Failed to read stored files", e);
+        }
+
+    }
+
+    @Override
+    public Path load(String filename) {
+        return rootLocation.resolve(filename);
+    }
+
+    @Override
+    public Resource loadAsResource(String filename) {
+        try {
+            Path file = load(filename);
+            Resource resource = new UrlResource(file.toUri());
+            if (resource.exists() || resource.isReadable()) {
+                return resource;
+            } else {
+                return null;
+            }
+        } catch (MalformedURLException e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    @Override
+    public void delete(String filename) {
+        Path file = load(filename);
+        try {
+            Files.delete(file);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    @Override
+    public String generateUrl(String keyName) {
+        String url = address + ":" + port + "/os/storage/fetch/" + keyName;
+        if (!url.startsWith("http")) {
+            url = "http://" + url;
+        }
+        return url;
+    }
+}

+ 30 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/storage/Storage.java

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

+ 60 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/storage/StorageService.java

@@ -0,0 +1,60 @@
+package org.linlinjava.litemall.core.storage;
+
+import org.springframework.core.io.Resource;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.nio.file.Path;
+import java.util.Map;
+import java.util.stream.Stream;
+
+public class StorageService {
+    private String active;
+    private Storage storage;
+    private Map<String, Storage> supportedStorage;
+
+    public String getActive() {
+        return active;
+    }
+
+    public void setActive(String active) {
+        this.active = active;
+        this.storage = this.supportedStorage.get(active);
+    }
+
+    public Map<String, Storage> getSupportedStorage() {
+        return supportedStorage;
+    }
+
+    public void setSupportedStorage(Map<String, Storage> supportedStorage) {
+        this.supportedStorage = supportedStorage;
+    }
+
+    /**
+     * 存储一个文件对象
+     * @param file      SpringBoot MultipartFile文件对象
+     * @param keyName   文件索引名
+     */
+    public void store(MultipartFile file, String keyName) {
+        storage.store(file, keyName);
+    }
+
+    public Stream<Path> loadAll() {
+        return storage.loadAll();
+    }
+
+    public Path load(String keyName) {
+        return storage.load(keyName);
+    }
+
+    public Resource loadAsResource(String keyName){
+        return storage.loadAsResource(keyName);
+    }
+
+    public void delete(String keyName){
+        storage.delete(keyName);
+    }
+
+    public String generateUrl(String keyName) {
+        return storage.generateUrl(keyName);
+    }
+}

+ 138 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/storage/TencentStorage.java

@@ -0,0 +1,138 @@
+package org.linlinjava.litemall.core.storage;
+
+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.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;
+
+/**
+ * 腾讯对象存储服务
+ */
+public class TencentStorage implements Storage {
+
+    private String secretId;
+    private String secretKey;
+    private String region;
+    private String bucketName;
+
+    private COSClient cosClient;
+
+    public String getSecretId() {
+        return secretId;
+    }
+
+    public void setSecretId(String secretId) {
+        this.secretId = secretId;
+    }
+
+    public String getSecretKey() {
+        return secretKey;
+    }
+
+    public void setSecretKey(String secretKey) {
+        this.secretKey = secretKey;
+    }
+
+    public String getRegion() {
+        return region;
+    }
+
+    public void setRegion(String region) {
+        this.region = region;
+    }
+
+    public String getBucketName() {
+        return bucketName;
+    }
+
+    public void setBucketName(String bucketName) {
+        this.bucketName = bucketName;
+    }
+
+    private COSClient getCOSClient() {
+        if (cosClient == null) {
+            // 1 初始化用户身份信息(secretId, secretKey)
+            COSCredentials cred = new BasicCOSCredentials(secretId, 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() {
+        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) {
+            ex.printStackTrace();
+        }
+    }
+
+    @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;
+    }
+}

+ 66 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/storage/config/StorageAutoConfiguration.java

@@ -0,0 +1,66 @@
+package org.linlinjava.litemall.core.storage.config;
+
+import org.apache.commons.collections.map.HashedMap;
+import org.linlinjava.litemall.core.storage.*;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+@EnableConfigurationProperties(StorageProperties.class)
+public class StorageAutoConfiguration {
+
+    private final StorageProperties properties;
+
+    public StorageAutoConfiguration(StorageProperties properties) {
+        this.properties = properties;
+    }
+
+    @Bean
+    public StorageService storageService() {
+        StorageService storageService = new StorageService();
+        Map<String, Storage> supportedStorage = new HashMap<String, Storage>(3);
+        supportedStorage.put("local", localStorage());
+        supportedStorage.put("aliyun", aliyunStorage());
+        supportedStorage.put("tencent", tencentStorage());
+        storageService.setSupportedStorage(supportedStorage);
+        String active = this.properties.getActive();
+        storageService.setActive(active);
+        return storageService;
+    }
+
+    @Bean
+    public LocalStorage localStorage() {
+        LocalStorage localStorage = new LocalStorage();
+        StorageProperties.Local local = this.properties.getLocal();
+        localStorage.setAddress(local.getAddress());
+        localStorage.setPort(local.getPort());
+        localStorage.setStoragePath(local.getStoragePath());
+        return localStorage;
+    }
+
+    @Bean
+    public AliyunStorage aliyunStorage() {
+        AliyunStorage aliyunStorage =  new AliyunStorage();
+        StorageProperties.Aliyun aliyun = this.properties.getAliyun();
+        aliyunStorage.setAccessKeyId(aliyun.getAccessKeyId());
+        aliyunStorage.setAccessKeySecret(aliyun.getAccessKeySecret());
+        aliyunStorage.setBucketName(aliyun.getBucketName());
+        aliyunStorage.setEndpoint(aliyun.getEndpoint());
+        return aliyunStorage;
+    }
+
+    @Bean
+    public TencentStorage tencentStorage() {
+        TencentStorage tencentStorage = new TencentStorage();
+        StorageProperties.Tencent tencent = this.properties.getTencent();
+        tencentStorage.setSecretId(tencent.getSecretId());
+        tencentStorage.setSecretKey(tencent.getSecretKey());
+        tencentStorage.setBucketName(tencent.getBucketName());
+        tencentStorage.setRegion(tencent.getRegion());
+        return tencentStorage;
+    }
+}

+ 151 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/storage/config/StorageProperties.java

@@ -0,0 +1,151 @@
+package org.linlinjava.litemall.core.storage.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+
+@ConfigurationProperties(prefix = "litemall.storage")
+public class StorageProperties {
+    private String active;
+    private Local local;
+    private Aliyun aliyun;
+    private Tencent tencent;
+
+    public String getActive() {
+        return active;
+    }
+
+    public void setActive(String active) {
+        this.active = active;
+    }
+
+    public Local getLocal() {
+        return local;
+    }
+
+    public void setLocal(Local local) {
+        this.local = local;
+    }
+
+    public Aliyun getAliyun() {
+        return aliyun;
+    }
+
+    public void setAliyun(Aliyun aliyun) {
+        this.aliyun = aliyun;
+    }
+
+    public Tencent getTencent() {
+        return tencent;
+    }
+
+    public void setTencent(Tencent tencent) {
+        this.tencent = tencent;
+    }
+
+    public static class Local {
+        private String address;
+        private String port;
+        private String storagePath;
+
+        public String getAddress() {
+            return address;
+        }
+
+        public void setAddress(String address) {
+            this.address = address;
+        }
+
+        public String getPort() {
+            return port;
+        }
+
+        public void setPort(String port) {
+            this.port = port;
+        }
+
+        public String getStoragePath() {
+            return storagePath;
+        }
+
+        public void setStoragePath(String storagePath) {
+            this.storagePath = storagePath;
+        }
+    }
+
+    public static class Tencent {
+        private String secretId;
+        private String secretKey;
+        private String region;
+        private String bucketName;
+
+        public String getSecretId() {
+            return secretId;
+        }
+
+        public void setSecretId(String secretId) {
+            this.secretId = secretId;
+        }
+
+        public String getSecretKey() {
+            return secretKey;
+        }
+
+        public void setSecretKey(String secretKey) {
+            this.secretKey = secretKey;
+        }
+
+        public String getRegion() {
+            return region;
+        }
+
+        public void setRegion(String region) {
+            this.region = region;
+        }
+
+        public String getBucketName() {
+            return bucketName;
+        }
+
+        public void setBucketName(String bucketName) {
+            this.bucketName = bucketName;
+        }
+    }
+
+    public static class Aliyun {
+        private  String endpoint;
+        private  String accessKeyId;
+        private  String accessKeySecret;
+        private  String bucketName;
+
+        public String getEndpoint() {
+            return endpoint;
+        }
+
+        public void setEndpoint(String endpoint) {
+            this.endpoint = endpoint;
+        }
+
+        public String getAccessKeyId() {
+            return accessKeyId;
+        }
+
+        public void setAccessKeyId(String accessKeyId) {
+            this.accessKeyId = accessKeyId;
+        }
+
+        public String getAccessKeySecret() {
+            return accessKeySecret;
+        }
+
+        public void setAccessKeySecret(String accessKeySecret) {
+            this.accessKeySecret = accessKeySecret;
+        }
+
+        public String getBucketName() {
+            return bucketName;
+        }
+
+        public void setBucketName(String bucketName) {
+            this.bucketName = bucketName;
+        }
+    }
+}

+ 24 - 1
litemall-core/src/main/resources/application-core.yml

@@ -70,4 +70,27 @@ litemall:
     - code: "FEDEX"
       name: "FEDEX联邦(国内件)"
     - code: "FEDEX_GJ"
-      name: "FEDEX联邦(国际件)"
+      name: "FEDEX联邦(国际件)"
+
+  # 对象存储配置
+  storage:
+    # 当前工作的对象存储模式,分别是local、aliyun、tencent
+    active: local
+    # 本地对象存储配置信息
+    local:
+      storagePath: storage
+      address: http://127.0.0.1
+      port: 8081
+    # 阿里云对象存储配置信息
+    aliyun:
+      endpoint: oss-cn-shenzhen.aliyuncs.com
+      accessKeyId: 111111
+      accessKeySecret: xxxxxx
+      bucketName: xxxxxx
+    # 腾讯对象存储配置信息
+    # 请参考 https://cloud.tencent.com/document/product/436/6249
+    tencent:
+      secretId: 111111
+      secretKey: xxxxxx
+      region: xxxxxx
+      bucketName: xxxxxx

+ 39 - 0
litemall-core/src/test/java/org/linlinjava/litemall/core/AliyunStorageTest.java

@@ -0,0 +1,39 @@
+package org.linlinjava.litemall.core;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.linlinjava.litemall.core.storage.AliyunStorage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.io.Resource;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+@WebAppConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest
+public class AliyunStorageTest {
+    @Autowired
+    private AliyunStorage aliyunStorage;
+
+    @Test
+    public void test() throws IOException {
+        String test = getClass().getClassLoader().getResource("litemall.png").getFile();
+        byte[] content =  (byte[])FileCopyUtils.copyToByteArray(new FileInputStream(test));
+        MockMultipartFile mockMultipartFile = new MockMultipartFile("litemall.png", "litemall.png", "image/png", content);
+        aliyunStorage.store(mockMultipartFile, "litemall.png");
+        Resource resource = aliyunStorage.loadAsResource("litemall.png");
+        String url = aliyunStorage.generateUrl("litemall.png");
+        System.out.println("test file " + test);
+        System.out.println("store file " + resource.getURI());
+        System.out.println("generate url " + url);
+
+//        tencentOsService.delete("litemall.png");
+    }
+
+}

+ 40 - 0
litemall-core/src/test/java/org/linlinjava/litemall/core/LocalStorageTest.java

@@ -0,0 +1,40 @@
+package org.linlinjava.litemall.core;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.linlinjava.litemall.core.storage.LocalStorage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.io.Resource;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+@WebAppConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest
+public class LocalStorageTest {
+    @Autowired
+    private LocalStorage localStorage;
+
+    @Test
+    public void test() throws IOException {
+        String test = getClass().getClassLoader().getResource("litemall.png").getFile();
+        byte[] content =  (byte[])FileCopyUtils.copyToByteArray(new FileInputStream(test));
+        MockMultipartFile mockMultipartFile = new MockMultipartFile("litemall.png", "litemall.png", "image/jpeg", content);
+        localStorage.store(mockMultipartFile, "litemall.png");
+        Resource resource = localStorage.loadAsResource("litemall.png");
+        String url = localStorage.generateUrl("litemall.png");
+        System.out.println("test file " + test);
+        System.out.println("store file " + resource.getURI());
+        System.out.println("generate url " + url);
+
+//        localStorage.delete("litemall.png");
+
+    }
+
+}

+ 39 - 0
litemall-core/src/test/java/org/linlinjava/litemall/core/TencentStorageTest.java

@@ -0,0 +1,39 @@
+package org.linlinjava.litemall.core;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.linlinjava.litemall.core.storage.TencentStorage;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.core.io.Resource;
+import org.springframework.mock.web.MockMultipartFile;
+import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
+import org.springframework.test.context.web.WebAppConfiguration;
+import org.springframework.util.FileCopyUtils;
+
+import java.io.FileInputStream;
+import java.io.IOException;
+
+@WebAppConfiguration
+@RunWith(SpringJUnit4ClassRunner.class)
+@SpringBootTest
+public class TencentStorageTest {
+    @Autowired
+    private TencentStorage tencentStorage;
+
+    @Test
+    public void test() throws IOException {
+        String test = getClass().getClassLoader().getResource("litemall.png").getFile();
+        byte[] content =  (byte[])FileCopyUtils.copyToByteArray(new FileInputStream(test));
+        MockMultipartFile mockMultipartFile = new MockMultipartFile("litemall.png", "litemall.png", "image/png", content);
+        tencentStorage.store(mockMultipartFile, "litemall.png");
+        Resource resource = tencentStorage.loadAsResource("litemall.png");
+        String url = tencentStorage.generateUrl("litemall.png");
+        System.out.println("test file " + test);
+        System.out.println("store file " + resource.getURI());
+        System.out.println("generate url " + url);
+
+//        tencentStorage.delete("litemall.png");
+    }
+
+}

BIN
litemall-core/src/test/resources/litemall.png