diff --git a/litemall-core/.gitignore b/litemall-core/.gitignore
index 94ceef7d..a1d85ecf 100644
--- a/litemall-core/.gitignore
+++ b/litemall-core/.gitignore
@@ -1,3 +1,4 @@
/target/
/litemall-core.iml
+/storage/
diff --git a/litemall-core/pom.xml b/litemall-core/pom.xml
index 63812d53..bf3b8e4d 100644
--- a/litemall-core/pom.xml
+++ b/litemall-core/pom.xml
@@ -38,6 +38,25 @@
qcloudsms
1.0.5
+
+
+ com.qcloud
+ cos_api
+ 5.4.4
+
+
+ slf4j-log4j12
+ org.slf4j
+
+
+
+
+
+ com.aliyun.oss
+ aliyun-sdk-oss
+ 2.5.0
+
+
com.github.binarywang
weixin-java-miniapp
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/AliyunStorage.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/AliyunStorage.java
new file mode 100644
index 00000000..84c8c175
--- /dev/null
+++ b/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 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;
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/LocalStorage.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/LocalStorage.java
new file mode 100644
index 00000000..e2922546
--- /dev/null
+++ b/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 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;
+ }
+}
\ No newline at end of file
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/Storage.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/Storage.java
new file mode 100644
index 00000000..58a769ef
--- /dev/null
+++ b/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 loadAll();
+
+ Path load(String keyName);
+
+ Resource loadAsResource(String keyName);
+
+ void delete(String keyName);
+
+ String generateUrl(String keyName);
+}
\ No newline at end of file
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/StorageService.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/StorageService.java
new file mode 100644
index 00000000..f6cee6f9
--- /dev/null
+++ b/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 supportedStorage;
+
+ public String getActive() {
+ return active;
+ }
+
+ public void setActive(String active) {
+ this.active = active;
+ this.storage = this.supportedStorage.get(active);
+ }
+
+ public Map getSupportedStorage() {
+ return supportedStorage;
+ }
+
+ public void setSupportedStorage(Map supportedStorage) {
+ this.supportedStorage = supportedStorage;
+ }
+
+ /**
+ * 存储一个文件对象
+ * @param file SpringBoot MultipartFile文件对象
+ * @param keyName 文件索引名
+ */
+ public void store(MultipartFile file, String keyName) {
+ storage.store(file, keyName);
+ }
+
+ public Stream 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);
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/TencentStorage.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/TencentStorage.java
new file mode 100644
index 00000000..505e270a
--- /dev/null
+++ b/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 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;
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/config/StorageAutoConfiguration.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/config/StorageAutoConfiguration.java
new file mode 100644
index 00000000..a9d08f41
--- /dev/null
+++ b/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 supportedStorage = new HashMap(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;
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/config/StorageProperties.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/storage/config/StorageProperties.java
new file mode 100644
index 00000000..b8b21f0d
--- /dev/null
+++ b/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;
+ }
+ }
+}
diff --git a/litemall-core/src/main/resources/application-core.yml b/litemall-core/src/main/resources/application-core.yml
index f2045547..7ee80e44 100644
--- a/litemall-core/src/main/resources/application-core.yml
+++ b/litemall-core/src/main/resources/application-core.yml
@@ -70,4 +70,27 @@ litemall:
- code: "FEDEX"
name: "FEDEX联邦(国内件)"
- code: "FEDEX_GJ"
- name: "FEDEX联邦(国际件)"
\ No newline at end of file
+ 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
\ No newline at end of file
diff --git a/litemall-core/src/test/java/org/linlinjava/litemall/core/AliyunStorageTest.java b/litemall-core/src/test/java/org/linlinjava/litemall/core/AliyunStorageTest.java
new file mode 100644
index 00000000..e5a949eb
--- /dev/null
+++ b/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");
+ }
+
+}
\ No newline at end of file
diff --git a/litemall-core/src/test/java/org/linlinjava/litemall/core/LocalStorageTest.java b/litemall-core/src/test/java/org/linlinjava/litemall/core/LocalStorageTest.java
new file mode 100644
index 00000000..aca78d04
--- /dev/null
+++ b/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");
+
+ }
+
+}
\ No newline at end of file
diff --git a/litemall-core/src/test/java/org/linlinjava/litemall/core/TencentStorageTest.java b/litemall-core/src/test/java/org/linlinjava/litemall/core/TencentStorageTest.java
new file mode 100644
index 00000000..fae0a9a9
--- /dev/null
+++ b/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");
+ }
+
+}
\ No newline at end of file
diff --git a/litemall-core/src/test/resources/litemall.png b/litemall-core/src/test/resources/litemall.png
new file mode 100644
index 00000000..d16e9afa
Binary files /dev/null and b/litemall-core/src/test/resources/litemall.png differ