diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
new file mode 100644
index 00000000..7a8f6f10
--- /dev/null
+++ b/.gitlab-ci.yml
@@ -0,0 +1,30 @@
+stages:
+ - deploy
+deploy:
+ stage: deploy
+ script:
+ - mvn install
+ - mvn clean package
+ - rm -rf /root/spring_boot/*.jar
+ - rm -rf /etc/init.d/litemall-*
+ - cp -rf litemall-admin-api/target/litemall-admin-api-*-exec.jar /root/spring_boot/litemall-admin-api.jar
+ - cp -rf litemall-os-api/target/litemall-os-api-*-exec.jar /root/spring_boot/litemall-os-api.jar
+ - cp -rf litemall-wx-api/target/litemall-wx-api-*-exec.jar /root/spring_boot/litemall-wx-api.jar
+ - sudo chmod 777 /root/spring_boot/*.jar
+ - sudo ln -f -s /root/spring_boot/litemall-admin-api.jar /etc/init.d/litemall-admin-api
+ - sudo ln -f -s /root/spring_boot/litemall-os-api.jar /etc/init.d/litemall-os-api
+ - sudo ln -f -s /root/spring_boot/litemall-wx-api.jar /etc/init.d/litemall-wx-api
+ - sudo /etc/init.d/litemall-os-api restart
+ - sudo /etc/init.d/litemall-wx-api restart
+ - sudo /etc/init.d/litemall-admin-api restart
+ - systemctl stop nginx
+ - rm -rf /root/nginx_web/
+ - cd litemall-admin
+ - cnpm install
+ - cnpm run build:dep
+ - mkdir /root/nginx_web
+ - cp -rf dist/* /root/nginx_web
+ - sudo chmod 777 /root/nginx_web
+ - systemctl restart nginx
+ tags:
+ - litemall_dev
\ No newline at end of file
diff --git a/litemall-admin-api/src/main/resources/application-dev.properties b/litemall-admin-api/src/main/resources/application-dev.properties
index 47db7700..500ee61d 100644
--- a/litemall-admin-api/src/main/resources/application-dev.properties
+++ b/litemall-admin-api/src/main/resources/application-dev.properties
@@ -3,7 +3,7 @@ pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
-spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false
+spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.username=litemall
spring.datasource.druid.password=litemall123456
diff --git a/litemall-admin/config/dep.env.js b/litemall-admin/config/dep.env.js
index 512f55d7..bfc41443 100644
--- a/litemall-admin/config/dep.env.js
+++ b/litemall-admin/config/dep.env.js
@@ -1,6 +1,6 @@
module.exports = {
NODE_ENV: '"production"',
ENV_CONFIG: '"dep"',
- BASE_API: '"http://122.152.206.172:8083/admin"',
- OS_API: '"http://122.152.206.172:8081/os"'
+ BASE_API: '"http://localhost:8083/admin"',
+ OS_API: '"http://localhost:8081/os"'
}
diff --git a/litemall-core/src/main/resources/notify.properties b/litemall-core/src/main/resources/notify.properties
index 5eabb730..313e3278 100644
--- a/litemall-core/src/main/resources/notify.properties
+++ b/litemall-core/src/main/resources/notify.properties
@@ -1,23 +1,23 @@
-# 邮件发送配置
+# \u90AE\u4EF6\u53D1\u9001\u914D\u7F6E
sprint.mail.enable=false
spring.mail.host=smtp.exmail.qq.com
spring.mail.username=xxxxxx
spring.mail.password=xxxxxx
spring.mail.sendto=example@qq.com
-# 短信发送配置
+# \u77ED\u4FE1\u53D1\u9001\u914D\u7F6E
spring.sms.enable=false
spring.sms.appid=111111
spring.sms.appkey=xxxxxx
spring.sms.sign=xxxxxx
-# 短信模板消息配置
-# 请在腾讯短信平台配置通知消息模板,然后这里设置不同短信模板ID
-# 请参考LitemallNotifyService.notifySMSTemplate
+# \u77ED\u4FE1\u6A21\u677F\u6D88\u606F\u914D\u7F6E
+# \u8BF7\u5728\u817E\u8BAF\u77ED\u4FE1\u5E73\u53F0\u914D\u7F6E\u901A\u77E5\u6D88\u606F\u6A21\u677F\uFF0C\u7136\u540E\u8FD9\u91CC\u8BBE\u7F6E\u4E0D\u540C\u77ED\u4FE1\u6A21\u677FID
+# \u8BF7\u53C2\u8003LitemallNotifyService.notifySMSTemplate
spring.sms.template.paySucceed=111111
spring.sms.template.captcha=222222
-# 发送线程池配置
+# \u53D1\u9001\u7EBF\u7A0B\u6C60\u914D\u7F6E
spring.notify.corePoolSize=5
spring.notify.maxPoolSize=100
spring.notify.queueCapacity=50
\ No newline at end of file
diff --git a/litemall-os-api/pom.xml b/litemall-os-api/pom.xml
index c8c69743..529eaac7 100644
--- a/litemall-os-api/pom.xml
+++ b/litemall-os-api/pom.xml
@@ -22,6 +22,13 @@
litemall-db
+
+ com.qcloud
+ cos_api
+ 5.4.4
+
+
+
diff --git a/litemall-os-api/src/main/java/org/linlinjava/litemall/os/service/FileSystemStorageService.java b/litemall-os-api/src/main/java/org/linlinjava/litemall/os/service/FileSystemStorageService.java
index 4e5729cb..3fef0c31 100644
--- a/litemall-os-api/src/main/java/org/linlinjava/litemall/os/service/FileSystemStorageService.java
+++ b/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;
+ }
}
\ No newline at end of file
diff --git a/litemall-os-api/src/main/java/org/linlinjava/litemall/os/service/StorageService.java b/litemall-os-api/src/main/java/org/linlinjava/litemall/os/service/StorageService.java
index e2126000..2354e9c1 100644
--- a/litemall-os-api/src/main/java/org/linlinjava/litemall/os/service/StorageService.java
+++ b/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 loadAll();
- Path load(String filename);
+ Path load(String keyName);
- Resource loadAsResource(String filename);
+ Resource loadAsResource(String keyName);
- void delete(String filename);
+ void delete(String keyName);
+
+ String generateUrl(String keyName);
}
\ No newline at end of file
diff --git a/litemall-os-api/src/main/java/org/linlinjava/litemall/os/tencent/TencentOSService.java b/litemall-os-api/src/main/java/org/linlinjava/litemall/os/tencent/TencentOSService.java
new file mode 100644
index 00000000..a3d02501
--- /dev/null
+++ b/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 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-os-api/src/main/java/org/linlinjava/litemall/os/web/OsStorageController.java b/litemall-os-api/src/main/java/org/linlinjava/litemall/os/web/OsStorageController.java
index 78cbe26b..451ce81c 100644
--- a/litemall-os-api/src/main/java/org/linlinjava/litemall/os/web/OsStorageController.java
+++ b/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());
diff --git a/litemall-os-api/src/main/resources/application-dev.properties b/litemall-os-api/src/main/resources/application-dev.properties
index 0c2f6f82..00479f2a 100644
--- a/litemall-os-api/src/main/resources/application-dev.properties
+++ b/litemall-os-api/src/main/resources/application-dev.properties
@@ -3,7 +3,7 @@ pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
-spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false
+spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.username=litemall
spring.datasource.druid.password=litemall123456
@@ -26,7 +26,7 @@ logging.level.org.mybatis=ERROR
logging.level.org.linlinjava.litemall.db=ERROR
logging.level.org.linlinjava.litemall=ERROR
-# 开发者应该设置成自己的域名,必须附带http或者https
-# 开发者可以查看OsStorageController.generateUrl
+# \u5F00\u53D1\u8005\u5E94\u8BE5\u8BBE\u7F6E\u6210\u81EA\u5DF1\u7684\u57DF\u540D\uFF0C\u5FC5\u987B\u9644\u5E26http\u6216\u8005https
+# \u5F00\u53D1\u8005\u53EF\u4EE5\u67E5\u770BOsStorageController.generateUrl
org.linlinjava.litemall.os.address=http://127.0.0.1
org.linlinjava.litemall.os.port=8081
\ No newline at end of file
diff --git a/litemall-os-api/src/main/resources/application.properties b/litemall-os-api/src/main/resources/application.properties
index b861699d..59eb1f3b 100644
--- a/litemall-os-api/src/main/resources/application.properties
+++ b/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
diff --git a/litemall-os-api/src/main/resources/tencent.properties b/litemall-os-api/src/main/resources/tencent.properties
new file mode 100644
index 00000000..435d03ba
--- /dev/null
+++ b/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=""
diff --git a/litemall-wx-api/src/main/resources/application-dev.properties b/litemall-wx-api/src/main/resources/application-dev.properties
index 5572b87a..d662f33e 100644
--- a/litemall-wx-api/src/main/resources/application-dev.properties
+++ b/litemall-wx-api/src/main/resources/application-dev.properties
@@ -3,7 +3,7 @@ pagehelper.reasonable=true
pagehelper.supportMethodsArguments=true
pagehelper.params=count=countSql
-spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false
+spring.datasource.druid.url=jdbc:mysql://localhost:3306/litemall?useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&verifyServerCertificate=false&useSSL=false&allowPublicKeyRetrieval=true
spring.datasource.druid.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.druid.username=litemall
spring.datasource.druid.password=litemall123456