如題, 專作記錄-雖然不太明白具體實現,以此作記錄php
注意: 如下具體配置均已混淆, 實際使用請使用真實配置信息;java
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
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; } } }
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; } }
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; } }
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("結束髮送"); } }