diff --git a/litemall-core/pom.xml b/litemall-core/pom.xml
index aadfb5dcc..9855ec359 100644
--- a/litemall-core/pom.xml
+++ b/litemall-core/pom.xml
@@ -42,9 +42,13 @@
javax.mail
+
+ com.github.qcloudsms
+ qcloudsms
+ 1.0.5
+
-
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/ExecutorConfig.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/ExecutorConfig.java
new file mode 100644
index 000000000..421a6b1ca
--- /dev/null
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/ExecutorConfig.java
@@ -0,0 +1,40 @@
+package org.linlinjava.litemall.core.notify;
+
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 异步线程池,用于异步发送通知
+ */
+@Configuration
+@EnableScheduling
+@EnableAsync
+class ExecutorConfig {
+
+ @Value("${spring.notify.corePoolSize}")
+ private int corePoolSize;
+ @Value("${spring.notify.maxPoolSize}")
+ private int maxPoolSize;
+ @Value("${spring.notify.queueCapacity}")
+ private int queueCapacity;
+
+ @Bean(name = "nofityAsync")
+ public Executor nofityAsync() {
+ ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+ executor.setCorePoolSize(corePoolSize);
+ executor.setMaxPoolSize(maxPoolSize);
+ executor.setQueueCapacity(queueCapacity);
+ executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+ executor.setThreadNamePrefix("NotifyExecutor-");
+ executor.initialize();
+ return executor;
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/LitemallNotifyService.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/LitemallNotifyService.java
new file mode 100644
index 000000000..52de1cef4
--- /dev/null
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/LitemallNotifyService.java
@@ -0,0 +1,69 @@
+package org.linlinjava.litemall.core.notify;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.core.env.Environment;
+import org.springframework.stereotype.Service;
+
+/**
+ * Litemall商城通知服务类
+ */
+@PropertySource(value = "classpath:notify.properties")
+@Service("litemallNotifyService")
+public class LitemallNotifyService {
+ @Autowired
+ MailSendService mailSendService;
+ @Autowired
+ SMSSendService smsSendService;
+ @Autowired
+ Environment environment;
+
+ @Value("${sprint.mail.enable}")
+ private boolean sendMailEnable;
+ @Value("${spring.sms.enable}")
+ private boolean sendSMSEnable;
+
+ public void notifySMSMessage(String phoneNumber,String message) {
+ if (!sendSMSEnable)
+ return;
+
+ smsSendService.sendSMS(phoneNumber, message);
+ }
+
+ /**
+ * 短信模版通知
+ * @param phoneNumber 接收通知的电话号码
+ * @param params 通知模版内容里的参数,类似"您的验证码为{1}"中{1}的值
+ * @param notifyType 通知类别,通过该枚举值在配置文件中获取相应的模版ID
+ */
+ public void notifySMSTemplate(String phoneNumber, String[] params, NotifyUtils.NotifyType notifyType) {
+ if (!sendSMSEnable)
+ return;
+
+ int templateId = -1;
+ switch (notifyType) {
+ case PAY_COMPLATED:
+ templateId = Integer.parseInt(environment.getProperty("spring.sms.template.pay.complated"));
+ break;
+ case VERIFICATIONCODE:
+ templateId = Integer.parseInt(environment.getProperty("spring.sms.template.verificationcode"));
+ break;
+ }
+
+ if (templateId != -1)
+ smsSendService.sendSMSWithTemplate(phoneNumber, templateId, params);
+ }
+
+ /**
+ * 发送邮件通知,接收者在spring.mail.sendto中指定
+ * @param setSubject 邮件标题
+ * @param setText 邮件内容
+ */
+ public void notifyMailMessage(String setSubject, String setText) {
+ if(!sendMailEnable)
+ return;
+
+ mailSendService.sendEmail(setSubject, setText);
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/MailSendService.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/MailSendService.java
new file mode 100644
index 000000000..3c8edac7f
--- /dev/null
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/MailSendService.java
@@ -0,0 +1,46 @@
+package org.linlinjava.litemall.core.notify;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.mail.javamail.JavaMailSender;
+import org.springframework.mail.javamail.MimeMessageHelper;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.mail.internet.MimeMessage;
+
+@PropertySource(value = "classpath:notify.properties")
+@Service("mailSendService")
+class MailSendService {
+ @Resource
+ private JavaMailSender mailSender;
+
+ @Value("${spring.mail.username}")
+ private String from;
+
+ @Value("${spring.mail.sendto}")
+ private String sendto;
+
+ /**
+ * 异步发送邮件通知
+ * @param setSubject 邮件标题
+ * @param setText 邮件内容
+ */
+ @Async("nofityAsync")
+ public void sendEmail(String setSubject, String setText) {
+ try {
+ final MimeMessage mimeMessage = mailSender.createMimeMessage();
+ final MimeMessageHelper message = new MimeMessageHelper(mimeMessage);
+
+ message.setFrom(from);
+ message.setTo(sendto);
+ message.setSubject(setSubject);
+ message.setText(setText);
+ mailSender.send(mimeMessage);
+
+ } catch (Exception ex) {
+
+ }
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/NotifyUtils.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/NotifyUtils.java
new file mode 100644
index 000000000..571d28e93
--- /dev/null
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/NotifyUtils.java
@@ -0,0 +1,10 @@
+package org.linlinjava.litemall.core.notify;
+
+public class NotifyUtils {
+ /**
+ * 该枚举定义了所有的需要通知的事件,调用通知时作为参数
+ */
+ public enum NotifyType {
+ PAY_COMPLATED, REGISTER, VERIFICATIONCODE,
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/SMSSendService.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/SMSSendService.java
new file mode 100644
index 000000000..95f79803d
--- /dev/null
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/SMSSendService.java
@@ -0,0 +1,64 @@
+package org.linlinjava.litemall.core.notify;
+
+import com.github.qcloudsms.SmsSingleSender;
+import com.github.qcloudsms.SmsSingleSenderResult;
+import com.github.qcloudsms.httpclient.HTTPException;
+import org.json.JSONException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.stereotype.Service;
+
+import java.io.IOException;
+
+@PropertySource(value = "classpath:notify.properties")
+@Service("smsSendService")
+class SMSSendService {
+ @Value("${spring.sms.appid}")
+ private int appid;
+
+ @Value("${spring.sms.appkey}")
+ private String appkey;
+
+ @Value("${spring.sms.sign}")
+ private String smsSign;
+
+ @Async("nofityAsync")
+ public void sendSMS(String phoneNumber, String content) {
+ try {
+ SmsSingleSender ssender = new SmsSingleSender(appid, appkey);
+ SmsSingleSenderResult result = ssender.send(0, "86", phoneNumber,
+ content, "", "");
+
+ System.out.println(result);
+ } catch (HTTPException e) {
+ // HTTP响应码错误
+ e.printStackTrace();
+ } catch (JSONException e) {
+ // json解析错误
+ e.printStackTrace();
+ } catch (IOException e) {
+ // 网络IO错误
+ e.printStackTrace();
+ }
+ }
+
+ @Async("nofityAsync")
+ public void sendSMSWithTemplate(String phoneNumber, int templateId, String[] params) {
+ try {
+ SmsSingleSender ssender = new SmsSingleSender(appid, appkey);
+ SmsSingleSenderResult result = ssender.sendWithParam("86", phoneNumber,
+ templateId, params, smsSign, "", ""); // 签名参数未提供或者为空时,会使用默认签名发送短信
+ System.out.println(result);
+ } catch (HTTPException e) {
+ // HTTP响应码错误
+ e.printStackTrace();
+ } catch (JSONException e) {
+ // json解析错误
+ e.printStackTrace();
+ } catch (IOException e) {
+ // 网络IO错误
+ e.printStackTrace();
+ }
+ }
+}
diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/WXTemplateMsgSendService.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/WXTemplateMsgSendService.java
new file mode 100644
index 000000000..cdaca41f1
--- /dev/null
+++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/notify/WXTemplateMsgSendService.java
@@ -0,0 +1,132 @@
+package org.linlinjava.litemall.core.notify;
+
+import org.json.JSONObject;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Service;
+
+import javax.net.ssl.*;
+import java.io.BufferedReader;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.OutputStream;
+import java.net.ConnectException;
+import java.net.URL;
+import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+/**
+ * 微信模版消息通知,未完成
+ */
+@PropertySource(value = "classpath:notify.properties")
+@Service("wxTemplateMsgSendService")
+public class WXTemplateMsgSendService {
+ /**
+ * 发送微信消息(模板消息)
+ *
+ * @param touser 用户 OpenID
+ * @param templatId 模板消息ID
+ * @param formId payId或者表单ID
+ * @param clickurl URL置空,则在发送后,点击模板消息会进入一个空白页面(ios),或无法点击(android)。
+ * @param topcolor 标题颜色
+ * @param data 详细内容
+ * @return
+ */
+ public String sendWechatMsgToUser(String token, String touser, String templatId, String formId, String clickurl, String topcolor, JSONObject data) {
+ String tmpurl = "https://api.weixin.qq.com/cgi-bin/message/wxopen/template/send?access_token=" + token;
+ JSONObject json = new JSONObject();
+ json.put("touser", touser);
+ json.put("template_id", templatId);
+ json.put("form_id", formId);
+ json.put("url", clickurl);
+ json.put("topcolor", topcolor);
+ json.put("data", data);
+ try {
+ JSONObject result = httpsRequest(tmpurl, "POST", json.toString());
+// log.info("发送微信消息返回信息:" + resultJson.get("errcode"));
+ String errmsg = (String) result.get("errmsg");
+ if (!"ok".equals(errmsg)) { //如果为errmsg为ok,则代表发送成功,公众号推送信息给用户了。
+ return "error";
+ }
+ } catch (Exception e) {
+ e.printStackTrace();
+ return "error";
+ }
+ return "success";
+ }
+
+ /**
+ * 发送https请求
+ *
+ * @param requestUrl 请求地址
+ * @param requestMethod 请求方式(GET、POST)
+ * @param outputStr 提交的数据
+ * @return JSONObject(通过JSONObject.get ( key)的方式获取json对象的属性值)
+ */
+ private JSONObject httpsRequest(String requestUrl, String requestMethod, String outputStr) {
+ JSONObject jsonObject = null;
+ try {
+ // 创建SSLContext对象,并使用我们指定的信任管理器初始化
+ TrustManager[] tm = {new MyX509TrustManager()};
+ SSLContext sslContext = SSLContext.getInstance("SSL", "SunJSSE");
+ sslContext.init(null, tm, new SecureRandom());
+ // 从上述SSLContext对象中得到SSLSocketFactory对象
+ SSLSocketFactory ssf = sslContext.getSocketFactory();
+ URL url = new URL(requestUrl);
+ HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
+ conn.setSSLSocketFactory(ssf);
+ conn.setDoOutput(true);
+ conn.setDoInput(true);
+ conn.setUseCaches(false);
+ // 设置请求方式(GET/POST)
+ conn.setRequestMethod(requestMethod);
+ // 当outputStr不为null时向输出流写数据
+ if (null != outputStr) {
+ OutputStream outputStream = conn.getOutputStream();
+ // 注意编码格式
+ outputStream.write(outputStr.getBytes("UTF-8"));
+ outputStream.close();
+ }
+ // 从输入流读取返回内容
+ InputStream inputStream = conn.getInputStream();
+ InputStreamReader inputStreamReader = new InputStreamReader(inputStream, "utf-8");
+ BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
+ String str = null;
+ StringBuffer buffer = new StringBuffer();
+ while ((str = bufferedReader.readLine()) != null) {
+ buffer.append(str);
+ }
+ // 释放资源
+ bufferedReader.close();
+ inputStreamReader.close();
+ inputStream.close();
+ inputStream = null;
+ conn.disconnect();
+ jsonObject = new JSONObject(buffer.toString());
+ } catch (ConnectException ce) {
+// log.error("连接超时:{}", ce);
+ } catch (Exception e) {
+// log.error("https请求异常:{}", e);
+ }
+ return jsonObject;
+ }
+
+ /**
+ * 微信请求 - 信任管理器
+ */
+ private class MyX509TrustManager implements X509TrustManager {
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ // return new X509Certificate[0];
+ return null;
+ }
+ }
+}
diff --git a/litemall-core/src/main/resources/application.properties b/litemall-core/src/main/resources/application.properties
index 257b30648..dd877f46b 100644
--- a/litemall-core/src/main/resources/application.properties
+++ b/litemall-core/src/main/resources/application.properties
@@ -1 +1,2 @@
-spring.profiles.active=dev
\ No newline at end of file
+spring.profiles.active=dev
+spring.message.encoding = UTF-8
\ No newline at end of file
diff --git a/litemall-core/src/main/resources/notify.properties b/litemall-core/src/main/resources/notify.properties
new file mode 100644
index 000000000..9579ab7a2
--- /dev/null
+++ b/litemall-core/src/main/resources/notify.properties
@@ -0,0 +1,22 @@
+
+#\u90AE\u4EF6\u53D1\u9001\u914D\u7F6E
+sprint.mail.enable=false
+spring.mail.host=smtp.exmail.qq.com
+spring.mail.username=ex@ex.com.cn
+spring.mail.password=
+spring.mail.sendto=ex@qq.com
+
+#\u77ED\u4FE1\u53D1\u9001\u914D\u7F6E
+spring.sms.enable=false
+spring.sms.appid=
+spring.sms.appkey=
+spring.sms.sign=
+
+#\u77ED\u4FE1\u6A21\u7248\u6D88\u606F\u914D\u7F6E\uFF0C\u8BF7\u5728\u817E\u8BAF\u77ED\u4FE1\u5E73\u53F0\u914D\u7F6E\u597D\u5404\u4E2A\u901A\u77E5\u6D88\u606F\u7684\u6A21\u7248\uFF0C\u7136\u540E\u5C06\u6A21\u7248ID\u4E00\u4E00\u8D4B\u503C,LitemallNotifyService,NotifyType\u679A\u4E3E\u4E2D\u4E0E\u8FD9\u91CC\u4E00\u4E00\u5BF9\u5E94
+spring.sms.template.pay.complated=156349
+spring.sms.template.verificationcode=156433
+
+#\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-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxOrderController.java b/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxOrderController.java
index ab5382752..ee1cd33e6 100644
--- a/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxOrderController.java
+++ b/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxOrderController.java
@@ -9,8 +9,9 @@
import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
+import org.linlinjava.litemall.core.notify.LitemallNotifyService;
+import org.linlinjava.litemall.core.notify.NotifyUtils;
import org.linlinjava.litemall.core.util.JacksonUtil;
-import org.linlinjava.litemall.core.util.MailUtils;
import org.linlinjava.litemall.core.util.ResponseUtil;
import org.linlinjava.litemall.db.domain.*;
import org.linlinjava.litemall.db.service.*;
@@ -80,6 +81,9 @@ public class WxOrderController {
@Autowired
private WxPayService wxPayService;
+ @Autowired
+ private LitemallNotifyService litemallNotifyService;
+
public WxOrderController() {
}
@@ -485,7 +489,7 @@ public Object prepay(@LoginUser Integer userId, @RequestBody String body, HttpSe
orderRequest.setOutTradeNo(order.getOrderSn());
orderRequest.setOpenid(openid);
// TODO 更有意义的显示名称
- orderRequest.setBody("litemall小商场-订单测试支付");
+ orderRequest.setBody("订单:" + order.getOrderSn());
// 元转成分
Integer fee = 0;
// 这里演示仅支付1分
@@ -552,8 +556,9 @@ public Object payNotify(HttpServletRequest request, HttpServletResponse response
order.setOrderStatus(OrderUtil.STATUS_PAY);
orderService.updateById(order);
- //TODO 发送邮件通知,这里最好才用异步发送
- MailUtils.getMailUtils().sendEmail("订单通知", order.toString());
+ //TODO 发送邮件和短信通知,这里采用异步发送
+ litemallNotifyService.notifyMailMessage("订单通知", order.toString());
+ litemallNotifyService.notifySMSTemplate(order.getMobile(), new String[]{""}, NotifyUtils.NotifyType.PAY_COMPLATED);
return WxPayNotifyResponse.success("处理成功!");
} catch (Exception e) {
@@ -715,5 +720,4 @@ public Object comment(@LoginUser Integer userId, Integer orderId, Integer goodsI
LitemallOrderGoods orderGoods = orderGoodsList.get(0);
return ResponseUtil.ok(orderGoods);
}
-
}
\ No newline at end of file