Browse Source

Merge branch 'master' of https://github.com/beaver383/litemall

beaver383 6 years ago
parent
commit
09c169c1ed

+ 11 - 2
deploy/litemall/application.yml

@@ -61,8 +61,10 @@ litemall:
     # 短信息用于通知客户,例如发货短信通知,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
     sms:
       enable: false
-      appid: 111111111
-      appkey: xxxxxxxxxxxxxx
+      # 如果是腾讯云短信,则设置active的值tencent
+      # 如果是阿里云短信,则设置active的值aliyun
+      active: tencent
+      sign: litemall
       template:
         - name: paySucceed
           templateId: 156349
@@ -72,6 +74,13 @@ litemall:
           templateId: 158002
         - name: refund
           templateId: 159447
+      tencent:
+        appid: 111111111
+        appkey: xxxxxxxxxxxxxx
+      aliyun:
+        regionId: xxx
+        accessKeyId: xxx
+        accessKeySecret: xxx
 
     # 微信模版通知配置
     # 微信模版用于通知客户或者运营者,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值

+ 51 - 25
doc/project.md

@@ -589,24 +589,33 @@ litemall:
     # 短信息用于通知客户,例如发货短信通知,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
     sms:
       enable: false
-      appid: 111111111
-      appkey: xxxxxxxxxxxxxx
+      # 如果是腾讯云短信,则设置active的值tencent
+      # 如果是阿里云短信,则设置active的值aliyun
+      active: tencent
+      sign: litemall
       template:
-      - name: paySucceed
-        templateId: 156349
-      - name: captcha
-        templateId: 156433
-      - name: ship
-        templateId: 158002
-      - name: refund
-        templateId: 159447
+        - name: paySucceed
+          templateId: 156349
+        - name: captcha
+          templateId: 156433
+        - name: ship
+          templateId: 158002
+        - name: refund
+          templateId: 159447
+      tencent:
+        appid: 111111111
+        appkey: xxxxxxxxxxxxxx
+      aliyun:
+        regionId: xxx
+        accessKeyId: xxx
+        accessKeySecret: xxx
 ```        
 
 配置方式:
-1. 腾讯云短信平台申请,然后设置四个场景的短信模板;
-2. 开发者在配置文件设置`enable`的值`true`,然后其他信息设置
-腾讯云短信平台申请的appid等值。
-这里只测试过腾讯云短信平台,开发者需要自行测试其他短信云平台。
+1. 腾讯云短信平台或者阿里云短信平台申请,然后设置四个场景的短信模板;
+2. 开发者在配置文件设置`enable`的值`true`,设置`active`的值`tencent`或`aliyun`
+3. 然后配置其他信息,例如腾讯云短信平台申请的appid等值。
+这里只测试过腾讯云短信平台和阿里云短信平台,开发者需要自行测试其他短信云平台。
 
 应用场景:
 目前短信通知场景只支持支付成功、验证码、订单发送、退款成功四种情况。
@@ -616,6 +625,17 @@ litemall:
 当配置好信息以后,开发者可以litemall-core模块的`SmsTest`测试类中设置手机号和
 模板所需要的参数值,独立启动`SmsTest`测试类发送短信,然后查看手机是否成功接收短信。
 
+短信模板参数命名:
+这里存在一个问题,即腾讯云短信的官方平台中申请短信模板格式的模板参数是数组,
+例如“你好,验证码是{0},时间是{1}"; 
+而阿里云短信的官方平台中申请短信模板的模板参数是JSON,
+例如“你好,验证码是{param1},时间是{param2}"。
+为了保持当前代码的通用性,本项目采用数组传递参数,而对阿里云申请模板的参数做了一定的假设:
+1. 腾讯云模块参数,申请模板时按照官方设置即可,例如“你好,验证码是{0},时间是{1}"; 
+2. 阿里云模板参数,本项目假定开发者在官方申请的参数格式应该采用"{ code: xxx, code1: xxx, code2: xxx }",
+例如“你好,验证码是{code},时间是{code1}"。开发者可以查看`AliyunSmsSender`类的`sendWithTemplate`方法的
+源代码即可理解。如果觉得不合理,可以自行调整相关代码。
+
 #### 1.4.5.7 微信通知配置
 
 微信通知是微信上收到的服务通知。
@@ -867,32 +887,38 @@ litemall:
 
     如果开发者设置SSH密钥,可以采用免密码登录;否则采用账号和密码登录。
     
-#### 1.5.1.2 JDK8
+#### 1.5.1.2 OpenJDK8
 
-https://www.digitalocean.com/community/tutorials/how-to-install-java-with-apt-get-on-ubuntu-16-04
+这里可以安装openjdk-8-jre
 
-http://www.webupd8.org/2012/09/install-oracle-java-8-in-ubuntu-via-ppa.html
+```bash
+sudo apt-get update
+sudo apt-get install openjdk-8-jre
+```
+
+如果希望采用jdk,而不是jre,则可以运行
 
 ```bash
-sudo add-apt-repository ppa:webupd8team/java
 sudo apt-get update
-sudo apt-get install oracle-java8-installer
-sudo apt-get install oracle-java8-set-default
+sudo apt-get install openjdk-8-jdk
 ```
 
-警告
-> "ppa:webupd8team/java" 不是Oracle官方PPA,可能存在安全隐患
+注意
+> 如果用户想采用Oracle JDK8或者其他JDK环境,请查阅相关资料安装
 
 #### 1.5.1.3 MySQL
 
-https://www.digitalocean.com/community/tutorials/how-to-install-mysql-on-ubuntu-16-04
-
 ```
 sudo apt-get update
 sudo apt-get install mysql-server
 sudo apt-get install mysql-client
 ```
-    
+
+如果配置MySQL,可以运行命令
+```
+mysql_secure_installation
+```
+
 #### 1.5.1.4 项目打包
 
 1. 在主机或者开发机打包项目到deploy;

+ 6 - 0
litemall-core/pom.xml

@@ -17,6 +17,12 @@
         </dependency>
 
         <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+            <version>4.0.3</version>
+        </dependency>
+
+        <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-web</artifactId>
         </dependency>

+ 122 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/AliyunSmsSender.java

@@ -0,0 +1,122 @@
+package org.linlinjava.litemall.core.notify;
+
+import com.aliyuncs.CommonRequest;
+import com.aliyuncs.CommonResponse;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.IAcsClient;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.exceptions.ServerException;
+import com.aliyuncs.http.MethodType;
+import com.aliyuncs.profile.DefaultProfile;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.linlinjava.litemall.core.util.JacksonUtil;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/*
+ * 阿里云短信服务
+ */
+public class AliyunSmsSender implements SmsSender {
+    private final Log logger = LogFactory.getLog(AliyunSmsSender.class);
+
+    private String regionId;
+    private String accessKeyId;
+    private String accessKeySecret;
+    private String sign;
+
+    public String getRegionId() {
+        return regionId;
+    }
+
+    public void setRegionId(String regionId) {
+        this.regionId = regionId;
+    }
+
+    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 getSign() {
+        return sign;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
+    }
+
+    @Override
+    public SmsResult send(String phone, String content) {
+        SmsResult smsResult = new SmsResult();
+        smsResult.setSuccessful(false);
+        return smsResult;
+    }
+
+    @Override
+    public SmsResult sendWithTemplate(String phone, String templateId, String[] params) {
+        DefaultProfile profile = DefaultProfile.getProfile(this.regionId, this.accessKeyId, this.accessKeySecret);
+        IAcsClient client = new DefaultAcsClient(profile);
+
+        CommonRequest request = new CommonRequest();
+        request.setMethod(MethodType.POST);
+        request.setDomain("dysmsapi.aliyuncs.com");
+        request.setVersion("2017-05-25");
+        request.setAction("SendSms");
+        request.putQueryParameter("RegionId", this.regionId);
+        request.putQueryParameter("PhoneNumbers", phone);
+        request.putQueryParameter("SignName", this.sign);
+        request.putQueryParameter("TemplateCode", templateId);
+        /*
+          NOTE:阿里云短信和腾讯云短信这里存在不一致
+          腾讯云短信模板参数是数组,因此短信模板形式如 “短信参数{1}, 短信参数{2}”
+          阿里云短信模板参数是JSON,因此短信模板形式如“短信参数{param1}, 短信参数{param2}”
+          为了保持统一,我们假定阿里云短信里面的参数是code,code1,code2...
+
+          如果开发者在阿里云短信申请的模板参数是其他命名,请开发者自行调整这里的代码,或者直接写死。
+         */
+        String templateParam = "{}";
+        if(params.length == 1){
+            Map<String, String> data = new HashMap<>();
+            data.put("code", params[0]);
+            templateParam = JacksonUtil.toJson(data);
+        }
+        else if(params.length > 1){
+            Map<String, String> data = new HashMap<>();
+            data.put("code", params[0]);
+            for(int i = 1; i < params.length; i++){
+                data.put("code" + i, params[i]);
+            }
+            templateParam = JacksonUtil.toJson(data);
+        }
+        request.putQueryParameter("TemplateParam", templateParam);
+
+        try {
+            CommonResponse response = client.getCommonResponse(request);
+            SmsResult smsResult = new SmsResult();
+            smsResult.setSuccessful(true);
+            smsResult.setResult(response);
+            return smsResult;
+        } catch (ServerException e) {
+            e.printStackTrace();
+        } catch (ClientException e) {
+            e.printStackTrace();
+        }
+
+        SmsResult smsResult = new SmsResult();
+        smsResult.setSuccessful(false);
+        return smsResult;
+    }
+}

+ 2 - 5
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/NotifyService.java

@@ -66,8 +66,7 @@ public class NotifyService {
             return;
         }
 
-        int templateId = Integer.parseInt(templateIdStr);
-        smsSender.sendWithTemplate(phoneNumber, templateId, params);
+        smsSender.sendWithTemplate(phoneNumber, templateIdStr, params);
     }
 
     /**
@@ -82,9 +81,7 @@ public class NotifyService {
         if (smsSender == null)
             return null;
 
-        int templateId = Integer.parseInt(getTemplateId(notifyType, smsTemplate));
-
-        return smsSender.sendWithTemplate(phoneNumber, templateId, params);
+        return smsSender.sendWithTemplate(phoneNumber, getTemplateId(notifyType, smsTemplate), params);
     }
 
     /**

+ 2 - 3
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/SmsSender.java

@@ -13,10 +13,9 @@ public interface SmsSender {
 
     /**
      * 通过短信模版发送短信息
-     *
-     * @param phone      接收通知的电话号码
+     *  @param phone      接收通知的电话号码
      * @param templateId 通知模板ID
      * @param params     通知模版内容里的参数,类似"您的验证码为{1}"中{1}的值
      */
-    SmsResult sendWithTemplate(String phone, int templateId, String[] params);
+    SmsResult sendWithTemplate(String phone, String templateId, String[] params);
 }

+ 13 - 4
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/TencentSmsSender.java

@@ -15,6 +15,7 @@ public class TencentSmsSender implements SmsSender {
     private final Log logger = LogFactory.getLog(TencentSmsSender.class);
 
     private SmsSingleSender sender;
+    private String sign;
 
     public SmsSingleSender getSender() {
         return sender;
@@ -38,13 +39,15 @@ public class TencentSmsSender implements SmsSender {
             logger.error(e.getMessage(), e);
         }
 
-        return null;
+        SmsResult smsResult = new SmsResult();
+        smsResult.setSuccessful(false);
+        return smsResult;
     }
 
     @Override
-    public SmsResult sendWithTemplate(String phone, int templateId, String[] params) {
+    public SmsResult sendWithTemplate(String phone, String templateId, String[] params) {
         try {
-            SmsSingleSenderResult result = sender.sendWithParam("86", phone, templateId, params, "", "", "");
+            SmsSingleSenderResult result = sender.sendWithParam("86", phone, Integer.parseInt(templateId), params, this.sign, "", "");
             logger.debug(result);
 
             SmsResult smsResult = new SmsResult();
@@ -55,6 +58,12 @@ public class TencentSmsSender implements SmsSender {
             logger.error(e.getMessage(), e);
         }
 
-        return null;
+        SmsResult smsResult = new SmsResult();
+        smsResult.setSuccessful(false);
+        return smsResult;
+    }
+
+    public void setSign(String sign) {
+        this.sign = sign;
     }
 }

+ 23 - 2
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/config/NotifyAutoConfiguration.java

@@ -1,6 +1,7 @@
 package org.linlinjava.litemall.core.notify.config;
 
 import com.github.qcloudsms.SmsSingleSender;
+import org.linlinjava.litemall.core.notify.AliyunSmsSender;
 import org.linlinjava.litemall.core.notify.NotifyService;
 import org.linlinjava.litemall.core.notify.TencentSmsSender;
 import org.linlinjava.litemall.core.notify.WxTemplateSender;
@@ -33,7 +34,13 @@ public class NotifyAutoConfiguration {
 
         NotifyProperties.Sms smsConfig = properties.getSms();
         if (smsConfig.isEnable()) {
-            notifyService.setSmsSender(tencentSmsSender());
+            if(smsConfig.getActive().equals("tencent")) {
+                notifyService.setSmsSender(tencentSmsSender());
+            }
+            else if(smsConfig.getActive().equals("aliyun")) {
+                notifyService.setSmsSender(aliyunSmsSender());
+            }
+
             notifyService.setSmsTemplate(smsConfig.getTemplate());
         }
 
@@ -65,7 +72,21 @@ public class NotifyAutoConfiguration {
     public TencentSmsSender tencentSmsSender() {
         NotifyProperties.Sms smsConfig = properties.getSms();
         TencentSmsSender smsSender = new TencentSmsSender();
-        smsSender.setSender(new SmsSingleSender(smsConfig.getAppid(), smsConfig.getAppkey()));
+        NotifyProperties.Sms.Tencent tencent = smsConfig.getTencent();
+        smsSender.setSender(new SmsSingleSender(tencent.getAppid(), tencent.getAppkey()));
+        smsSender.setSign(smsConfig.getSign());
+        return smsSender;
+    }
+
+    @Bean
+    public AliyunSmsSender aliyunSmsSender() {
+        NotifyProperties.Sms smsConfig = properties.getSms();
+        AliyunSmsSender smsSender = new AliyunSmsSender();
+        NotifyProperties.Sms.Aliyun aliyun = smsConfig.getAliyun();
+        smsSender.setSign(smsConfig.getSign());
+        smsSender.setRegionId(aliyun.getRegionId());
+        smsSender.setAccessKeyId(aliyun.getAccessKeyId());
+        smsSender.setAccessKeySecret(aliyun.getAccessKeySecret());
         return smsSender;
     }
 }

+ 83 - 14
litemall-core/src/main/java/org/linlinjava/litemall/core/notify/config/NotifyProperties.java

@@ -95,8 +95,10 @@ public class NotifyProperties {
 
     public static class Sms {
         private boolean enable;
-        private int appid;
-        private String appkey;
+        private String active;
+        private String sign;
+        private Tencent tencent;
+        private Aliyun aliyun;
         private List<Map<String, String>> template = new ArrayList<>();
 
         public boolean isEnable() {
@@ -107,28 +109,95 @@ public class NotifyProperties {
             this.enable = enable;
         }
 
-        public int getAppid() {
-            return appid;
+        public List<Map<String, String>> getTemplate() {
+            return template;
         }
 
-        public void setAppid(int appid) {
-            this.appid = appid;
+        public void setTemplate(List<Map<String, String>> template) {
+            this.template = template;
         }
 
-        public String getAppkey() {
-            return appkey;
+        public String getActive() {
+            return active;
         }
 
-        public void setAppkey(String appkey) {
-            this.appkey = appkey;
+        public void setActive(String active) {
+            this.active = active;
         }
 
-        public List<Map<String, String>> getTemplate() {
-            return template;
+        public String getSign() {
+            return sign;
         }
 
-        public void setTemplate(List<Map<String, String>> template) {
-            this.template = template;
+        public void setSign(String sign) {
+            this.sign = sign;
+        }
+
+        public Tencent getTencent() {
+            return tencent;
+        }
+
+        public void setTencent(Tencent tencent) {
+            this.tencent = tencent;
+        }
+
+        public Aliyun getAliyun() {
+            return aliyun;
+        }
+
+        public void setAliyun(Aliyun aliyun) {
+            this.aliyun = aliyun;
+        }
+
+        public static class Tencent {
+            private int appid;
+            private String appkey;
+
+            public int getAppid() {
+                return appid;
+            }
+
+            public void setAppid(int appid) {
+                this.appid = appid;
+            }
+
+            public String getAppkey() {
+                return appkey;
+            }
+
+            public void setAppkey(String appkey) {
+                this.appkey = appkey;
+            }
+        }
+
+        public static class Aliyun {
+            private String regionId;
+            private String accessKeyId;
+            private String accessKeySecret;
+
+            public String getRegionId() {
+                return regionId;
+            }
+
+            public void setRegionId(String regionId) {
+                this.regionId = regionId;
+            }
+
+            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;
+            }
         }
     }
 

+ 10 - 0
litemall-core/src/main/java/org/linlinjava/litemall/core/util/JacksonUtil.java

@@ -1,5 +1,6 @@
 package org.linlinjava.litemall.core.util;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.core.type.TypeReference;
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.ObjectMapper;
@@ -161,4 +162,13 @@ public class JacksonUtil {
         return null;
     }
 
+    public static String toJson(Object data) {
+        ObjectMapper objectMapper = new ObjectMapper();
+        try {
+            return objectMapper.writeValueAsString(data);
+        } catch (JsonProcessingException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
 }

+ 17 - 7
litemall-core/src/main/resources/application-core.yml

@@ -25,8 +25,10 @@ litemall:
     # 短信息用于通知客户,例如发货短信通知,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
     sms:
       enable: false
-      appid: 111111111
-      appkey: xxxxxxxxxxxxxx
+      # 如果是腾讯云短信,则设置active的值tencent
+      # 如果是阿里云短信,则设置active的值aliyun
+      active: tencent
+      sign: litemall
       template:
       - name: paySucceed
         templateId: 156349
@@ -36,6 +38,14 @@ litemall:
         templateId: 158002
       - name: refund
         templateId: 159447
+      tencent:
+        appid: 111111111
+        appkey: xxxxxxxxxxxxxx
+      aliyun:
+        regionId: xxx
+        accessKeyId: xxx
+        accessKeySecret: xxx
+
 
     # 微信模版通知配置
     # 微信模版用于通知客户或者运营者,注意配置格式;template-name,template-templateId 请参考 NotifyType 枚举值
@@ -87,7 +97,7 @@ litemall:
   # 对象存储配置
   storage:
     # 当前工作的对象存储模式,分别是local、aliyun、tencent、qiniu
-    active: local
+    active: tencent
     # 本地对象存储配置信息
     local:
       storagePath: storage
@@ -102,10 +112,10 @@ litemall:
     # 腾讯对象存储配置信息
     # 请参考 https://cloud.tencent.com/document/product/436/6249
     tencent:
-      secretId: 111111
-      secretKey: xxxxxx
-      region: xxxxxx
-      bucketName: litemall
+      secretId: AKIDOccMr856uoU1Tsa2MQL5aqseBUWRrb5i
+      secretKey: XqtgEhIdrupTs4ygaWlkUUXv3w3FiwuD
+      region: ap-shanghai
+      bucketName: vytech-1300096589
     # 七牛云对象存储配置信息
     qiniu:
       endpoint: http://pd5cb6ulu.bkt.clouddn.com

+ 1 - 1
pom.xml

@@ -115,7 +115,7 @@
             <dependency>
                 <groupId>com.qcloud</groupId>
                 <artifactId>cos_api</artifactId>
-                <version>5.4.4</version>
+                <version>5.6.8</version>
             </dependency>
 
             <dependency>