工廠類的使用,不關心底層實現工具, 外層只負責調用

如題, 專作記錄-雖然不太明白具體實現,以此作記錄php

設計結構

 

注意: 如下具體配置均已混淆, 實際使用請使用真實配置信息;java

配置yml

litemall:
  # 開發者應該設置成本身的wx相關信息
  wx:
    app-id: wx4d5ef10fb90757SS
    app-secret: b8cc185ca92b311e0c8fee85c89062SS
    mch-id: 1560901111
    mch-key: 111111111111111111111111111111
    notify-url: https://www.xxxx.vip/qdd/wx/order/pay-notify
    # 商戶證書文件路徑
    # 請參考「商戶證書」一節 https://pay.weixin.qq.com/wiki/doc/api/wxa/wxa_api.php?chapter=4_3
    key-path: xxxxx

  #通知相關配置
  notify:
    mail:
      # 郵件通知配置,郵箱通常用於接收業務通知例如收到新的訂單,sendto 定義郵件接收者,一般爲商城運營人員
      enable: false
      host: smtp.exmail.qq.com
      username: ex@ex.com.cn
      password: XXXXXXXXXXXXX
      sendfrom: ex@ex.com.cn
      sendto: ex@qq.com

    # 短消息模版通知配置
    # 短信息用於通知客戶,例如發貨短信通知,注意配置格式;template-name,template-templateId 請參考 NotifyType 枚舉值
    sms:
      enable: true      
      # 若是是騰訊雲短信,則設置active的值tencent
      # 若是是阿里雲短信,則設置active的值aliyun
      active: aliyun
      tencent:
        appid: 111111111
        appkey: xxxxxxxxxxxxxx
      aliyun:
        regionId: cn-hangzhou
        accessKeyId: LTAI4Fc5aio7M474NCfaXXX
        accessKeySecret: KiqZzpQz3Mcl6xrfpFSj6Kd80bXXXX
      sign: XX科技
      template:
      - name: paySucceed
        templateId: 156300
      - name: captcha
        templateId: 156400
      - name: ship
        templateId: SMS_177552500
      - name: refund
        templateId: 159447
      - name: reviewTimeOut
        templateId: SMS_177547600
      - name: reviewShip
        templateId: SMS_177542600
      - name: reviewSucceed
        templateId: SMS_177537600
      - name: payNotify
        templateId: SMS_177537600

    # 微信模版通知配置
    # 微信模版用於通知客戶或者運營者,注意配置格式;template-name,template-templateId 請參考 NotifyType 枚舉值
    wx:
      enable: false
      template:
      - name: paySucceed
        templateId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
      - name: captcha
        templateId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
      - name: ship
        templateId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
      - name: refund
        templateId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

與配置映射的java類型

package org.linlinjava.litemall.core.notify.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

@ConfigurationProperties(prefix = "litemall.notify")
public class NotifyProperties {
    private Mail mail;
    private Sms sms;
    private Wx wx;

    public Mail getMail() {
        return mail;
    }

    public void setMail(Mail mail) {
        this.mail = mail;
    }

    public Sms getSms() {
        return sms;
    }

    public void setSms(Sms sms) {
        this.sms = sms;
    }

    public Wx getWx() {
        return wx;
    }

    public void setWx(Wx wx) {
        this.wx = wx;
    }

    public static class Mail {
        private boolean enable;
        private String host;
        private String username;
        private String password;
        private String sendfrom;
        private String sendto;

        public boolean isEnable() {
            return enable;
        }

        public void setEnable(boolean enable) {
            this.enable = enable;
        }

        public String getHost() {
            return host;
        }

        public void setHost(String host) {
            this.host = host;
        }

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getPassword() {
            return password;
        }

        public void setPassword(String password) {
            this.password = password;
        }

        public String getSendfrom() {
            return sendfrom;
        }

        public void setSendfrom(String sendfrom) {
            this.sendfrom = sendfrom;
        }

        public String getSendto() {
            return sendto;
        }

        public void setSendto(String sendto) {
            this.sendto = sendto;
        }
    }

    public static class Sms {
        private boolean enable;
        private String active;
        private String sign;
        private Tencent tencent;
        private Aliyun aliyun;
        private List<Map<String, String>> template = new ArrayList<>();

        public boolean isEnable() {
            return enable;
        }

        public void setEnable(boolean enable) {
            this.enable = enable;
        }

        public List<Map<String, String>> getTemplate() {
            return template;
        }

        public void setTemplate(List<Map<String, String>> template) {
            this.template = template;
        }

        public String getActive() {
            return active;
        }

        public void setActive(String active) {
            this.active = active;
        }

        public String getSign() {
            return sign;
        }

        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;
            }
        }
    }

    public static class Wx {
        private boolean enable;
        private List<Map<String, String>> template = new ArrayList<>();

        public boolean isEnable() {
            return enable;
        }

        public void setEnable(boolean enable) {
            this.enable = enable;
        }

        public List<Map<String, String>> getTemplate() {
            return template;
        }

        public void setTemplate(List<Map<String, String>> template) {
            this.template = template;
        }
    }

}

讀取配置的java 類

 

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;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.JavaMailSenderImpl;

@Configuration
@EnableConfigurationProperties(NotifyProperties.class)
public class NotifyAutoConfiguration {

    private final NotifyProperties properties;

    public NotifyAutoConfiguration(NotifyProperties properties) {
        this.properties = properties;
    }

    @Bean
    public NotifyService notifyService() {
        NotifyService notifyService = new NotifyService();

        NotifyProperties.Mail mailConfig = properties.getMail();
        if (mailConfig.isEnable()) {
            notifyService.setMailSender(mailSender());
            notifyService.setSendFrom(mailConfig.getSendfrom());
            notifyService.setSendTo(mailConfig.getSendto());
        }

        NotifyProperties.Sms smsConfig = properties.getSms();
        if (smsConfig.isEnable()) {
            if(smsConfig.getActive().equals("tencent")) {
                notifyService.setSmsSender(tencentSmsSender());
            }
            else if(smsConfig.getActive().equals("aliyun")) {
                notifyService.setSmsSender(aliyunSmsSender());
            }

            notifyService.setSmsTemplate(smsConfig.getTemplate());
        }

        NotifyProperties.Wx wxConfig = properties.getWx();
        if (wxConfig.isEnable()) {
            notifyService.setWxTemplateSender(wxTemplateSender());
            notifyService.setWxTemplate(wxConfig.getTemplate());
        }
        return notifyService;
    }

    @Bean
    public JavaMailSender mailSender() {
        NotifyProperties.Mail mailConfig = properties.getMail();
        JavaMailSenderImpl mailSender = new JavaMailSenderImpl();
        mailSender.setHost(mailConfig.getHost());
        mailSender.setUsername(mailConfig.getUsername());
        mailSender.setPassword(mailConfig.getPassword());
        return mailSender;
    }

    @Bean
    public WxTemplateSender wxTemplateSender() {
        WxTemplateSender wxTemplateSender = new WxTemplateSender();
        return wxTemplateSender;
    }

    @Bean
    public TencentSmsSender tencentSmsSender() {
        NotifyProperties.Sms smsConfig = properties.getSms();
        TencentSmsSender smsSender = new TencentSmsSender();
        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;
    }
}

發送動做: 抽象java類

package org.linlinjava.litemall.core.notify;

public interface SmsSender {

    /**
     * 發送短信息
     *
     * @param phone   接收通知的電話號碼
     * @param content 短消息內容
     */
    SmsResult send(String phone, String content);


    /**
     * 經過短信模版發送短信息
     *
     * @param phone      接收通知的電話號碼
     * @param templateId 通知模板ID
     * @param params     通知模版內容裏的參數,相似"您的驗證碼爲{1}"中{1}的值
     */
    SmsResult sendWithTemplate(String phone, String templateId, String[] params);
}

 

實際發送類: 騰訊短信, 阿里雲短信....

package org.linlinjava.litemall.core.notify;

import com.github.qcloudsms.SmsSingleSender;
import com.github.qcloudsms.SmsSingleSenderResult;
import com.github.qcloudsms.httpclient.HTTPException;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;

/*
 * 騰訊雲短信服務
 */
@Slf4j
public class TencentSmsSender implements SmsSender {

    private SmsSingleSender sender;
    private String sign;

    public SmsSingleSender getSender() {
        return sender;
    }

    public void setSender(SmsSingleSender sender) {
        this.sender = sender;
    }

    @Override
    public SmsResult send(String phone, String content) {
        try {
            SmsSingleSenderResult result = sender.send(0, "86", phone, content, "", "");
            log.debug(result.toString());

            SmsResult smsResult = new SmsResult();
            smsResult.setSuccessful(true);
            smsResult.setResult(result);
            return smsResult;
        } catch (HTTPException | IOException e) {
            log.error(e.getMessage(), e);
        }

        SmsResult smsResult = new SmsResult();
        smsResult.setSuccessful(false);
        return smsResult;
    }

    @Override
    public SmsResult sendWithTemplate(String phone, String templateId, String[] params) {
        try {
            SmsSingleSenderResult result = sender.sendWithParam("86", phone, Integer.parseInt(templateId), params, this.sign, "", "");
            log.debug(result.toString());

            SmsResult smsResult = new SmsResult();
            smsResult.setSuccessful(true);
            smsResult.setResult(result);
            return smsResult;
        } catch (HTTPException | IOException e) {
            log.error(e.getMessage(), e);
        }

        SmsResult smsResult = new SmsResult();
        smsResult.setSuccessful(false);
        return smsResult;
    }

    public void setSign(String sign) {
        this.sign = sign;
    }
}
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 com.aliyuncs.profile.IClientProfile;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.linlinjava.litemall.core.util.JacksonUtil;

import java.util.HashMap;
import java.util.Map;

/*
 * 阿里雲短信服務
 */
@Slf4j
public class AliyunSmsSender implements SmsSender {

    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) {
        IClientProfile profile = DefaultProfile.getProfile(this.regionId, this.accessKeyId, this.accessKeySecret);
        IAcsClient client = null;
        try{
        client = new DefaultAcsClient(profile);
       } catch (Exception e){
            e.printStackTrace();
           log.error("打印異常: "+ ExceptionUtils.getStackTrace(e));
       }

        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);
            log.debug("發送成功: 發送結果:"+smsResult);
            return smsResult;
        } catch (ServerException e) {
            e.printStackTrace();
        } catch (ClientException e) {
            e.printStackTrace();
        }

        SmsResult smsResult = new SmsResult();
        smsResult.setSuccessful(false);
        log.debug("發送失敗: 發送結果:"+smsResult);
        return smsResult;
    }
}
package org.linlinjava.litemall.core.notify;

import cn.binarywang.wx.miniapp.api.WxMaService;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateData;
import cn.binarywang.wx.miniapp.bean.WxMaTemplateMessage;
import lombok.extern.slf4j.Slf4j;
import org.linlinjava.litemall.db.domain.LitemallUserFormid;
import org.linlinjava.litemall.db.service.LitemallUserFormIdService;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.ArrayList;
import java.util.List;

/**
 * 微信模版消息通知
 */
@Slf4j
public class WxTemplateSender {

    @Autowired
    private WxMaService wxMaService;

    @Autowired
    private LitemallUserFormIdService formIdService;

    /**
     * 發送微信消息(模板消息),不帶跳轉
     *
     * @param touser    用戶 OpenID
     * @param templatId 模板消息ID
     * @param parms     詳細內容
     */
    public void sendWechatMsg(String touser, String templatId, String[] parms) {
        sendMsg(touser, templatId, parms, "", "", "");
    }

    /**
     * 發送微信消息(模板消息),帶跳轉
     *
     * @param touser    用戶 OpenID
     * @param templatId 模板消息ID
     * @param parms     詳細內容
     * @param page      跳轉頁面
     */
    public void sendWechatMsg(String touser, String templatId, String[] parms, String page) {
        sendMsg(touser, templatId, parms, page, "", "");
    }

    private void sendMsg(String touser, String templatId, String[] parms, String page, String color,
                         String emphasisKeyword) {
        LitemallUserFormid userFormid = formIdService.queryByOpenId(touser);
        if (userFormid == null)
            return;


        WxMaTemplateMessage msg = new WxMaTemplateMessage();
        msg.setTemplateId(templatId);
        msg.setToUser(touser);
        msg.setFormId(userFormid.getFormid());
        msg.setPage(page);
        msg.setColor(color);
        msg.setEmphasisKeyword(emphasisKeyword);
        msg.setData(createMsgData(parms));

        try {
            wxMaService.getMsgService().sendTemplateMsg(msg);
            if (formIdService.updateUserFormId(userFormid) == 0) {
                log.warn("更新數據已失效");
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    private List<WxMaTemplateData> createMsgData(String[] parms) {
        List<WxMaTemplateData> dataList = new ArrayList<WxMaTemplateData>();
        for (int i = 1; i <= parms.length; i++) {
            dataList.add(new WxMaTemplateData("keyword" + i, parms[i - 1]));
        }

        return dataList;
    }
}

其餘: 枚舉類型,返回結果等java類

package org.linlinjava.litemall.core.notify;

public enum NotifyType {
    PAY_SUCCEED("paySucceed"), //支付成功通知
    SHIP("ship"), // 發貨通知
    REFUND("refund"),
    CAPTCHA("captcha"), // 小程序後臺服務驗證碼不支持
    PAY_TIMEOUT("payTimeOut"), //訂單支付超時提醒
    REVIEW_TIMEOUT("reviewTimeOut"), //評鑑超時提醒
    REVIEW_SHIP("reviewShip"), //評鑑發貨通知
    REVIEW_SUCCEED("reviewSucceed"), //評鑑審覈成功
    PAY_NOTIFY("payNotify") // 支付成功通知
    ;
    private String type;

    NotifyType(String type) {
        this.type = type;
    }

    public String getType() {
        return this.type;
    }
}
package org.linlinjava.litemall.core.notify;

/**
 * 發送短信的返回結果
 */
public class SmsResult {
    private boolean successful;
    private Object result;

    /**
     * 短信是否發送成功
     *
     * @return
     */
    public boolean isSuccessful() {
        return successful;
    }

    public void setSuccessful(boolean successful) {
        this.successful = successful;
    }

    public Object getResult() {
        return result;
    }

    public void setResult(Object result) {
        this.result = result;
    }
}

 

發送測試類

package org.linlinjava.litemall.admin;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.linlinjava.litemall.core.notify.NotifyService;
import org.linlinjava.litemall.core.notify.NotifyType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.core.env.Environment;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;

@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest
public class AdminConfigTest {
    @Autowired
    private Environment environment;

    @Autowired
    private NotifyService notifyService;

    @Test
    public void test() {
        // 測試獲取application-core.yml配置信息
        System.out.println(environment.getProperty("litemall.express.appId"));
        // 測試獲取application-db.yml配置信息
        System.out.println(environment.getProperty("spring.datasource.druid.url"));
        // 測試獲取application-admin.yml配置信息
        // System.out.println(environment.getProperty(""));
        // 測試獲取application.yml配置信息
        System.out.println(environment.getProperty("logging.level.org.linlinjava.litemall.admin"));
    }
    @Test
    public void testSend() {
        System.out.println("開始發送");
        //TODO 發送郵件和短信通知,這裏採用異步發送
        // 發貨會發送通知短信給用戶:          *
        // "您的訂單已經發貨,快遞公司 {1},快遞單 {2} ,請注意查收"
        notifyService.notifySmsTemplate("187581512XX", NotifyType.SHIP, new String[]{"STO", "3718162138269"});

        System.out.println("結束髮送");

    }
}
相關文章
相關標籤/搜索