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