From acdf7a65ff8804e6525adacf0115e2a38aa6113e Mon Sep 17 00:00:00 2001 From: Menethil Date: Sat, 14 Jul 2018 11:51:33 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E9=82=AE=E7=AE=B1?= =?UTF-8?q?=E5=B7=A5=E5=85=B7=E7=B1=BB=E5=8F=8A=E6=94=AF=E4=BB=98=E5=AE=8C?= =?UTF-8?q?=E6=88=90=E5=8F=91=E9=80=81=E9=82=AE=E4=BB=B6=E6=8F=90=E9=86=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- litemall-core/pom.xml | 10 ++++ .../litemall/core/util/MailUtils.java | 52 +++++++++++++++++++ litemall-wx-api/pom.xml | 5 ++ .../linlinjava/litemall/wx/util/IpUtil.java | 40 ++++++++++++++ .../litemall/wx/web/WxOrderController.java | 41 ++++++++------- 5 files changed, 128 insertions(+), 20 deletions(-) create mode 100644 litemall-core/src/main/java/org/linlinjava/litemall/core/util/MailUtils.java diff --git a/litemall-core/pom.xml b/litemall-core/pom.xml index 4792d401..aadfb5dc 100644 --- a/litemall-core/pom.xml +++ b/litemall-core/pom.xml @@ -31,6 +31,16 @@ io.springfox springfox-swagger-ui + + org.springframework + spring-context-support + RELEASE + compile + + + com.sun.mail + javax.mail + diff --git a/litemall-core/src/main/java/org/linlinjava/litemall/core/util/MailUtils.java b/litemall-core/src/main/java/org/linlinjava/litemall/core/util/MailUtils.java new file mode 100644 index 00000000..15d34c85 --- /dev/null +++ b/litemall-core/src/main/java/org/linlinjava/litemall/core/util/MailUtils.java @@ -0,0 +1,52 @@ +package org.linlinjava.litemall.core.util; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.mail.javamail.JavaMailSenderImpl; +import org.springframework.mail.javamail.MimeMessageHelper; + +import javax.mail.internet.MimeMessage; + +public class MailUtils { + private static final Log logger = LogFactory.getLog(MailUtils.class); + private static MailUtils mailUtils; + + private JavaMailSenderImpl mailSender; + + // TODO 邮箱相关后置后续应移到数据库,在后台配置完成,暂时先完成功能 + // 通知邮件送达地址 + private static final String SEND_TO = "ex@qq.com"; + + private MailUtils() { + mailSender = new JavaMailSenderImpl(); + // 配置发送邮箱设置,请按照自己邮箱填写 + mailSender.setHost("smtp.exmail.qq.com"); + mailSender.setUsername("ex@ex.com.cn"); + mailSender.setPassword("ex"); + mailSender.setDefaultEncoding("UTF-8"); + } + + public static MailUtils getMailUtils() { + if (mailUtils == null) + mailUtils = new MailUtils(); + + return mailUtils; + } + + public boolean sendEmail(String setSubject, String setText) { + try { + final MimeMessage mimeMessage = mailSender.createMimeMessage(); + final MimeMessageHelper message = new MimeMessageHelper(mimeMessage); + message.setFrom(mailSender.getUsername()); + message.setTo(SEND_TO); + message.setSubject(setSubject); + message.setText(setText); + mailSender.send(mimeMessage); + + return true; + } catch (Exception ex) { + logger.error("通知邮件发送出错" + ex.getMessage()); + return false; + } + } +} diff --git a/litemall-wx-api/pom.xml b/litemall-wx-api/pom.xml index 901bde4d..43c6bb31 100644 --- a/litemall-wx-api/pom.xml +++ b/litemall-wx-api/pom.xml @@ -16,6 +16,11 @@ + + org.springframework.boot + spring-boot-starter-mail + + org.linlinjava litemall-core diff --git a/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/util/IpUtil.java b/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/util/IpUtil.java index ebb3d803..f0b6412d 100644 --- a/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/util/IpUtil.java +++ b/litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/util/IpUtil.java @@ -1,6 +1,8 @@ package org.linlinjava.litemall.wx.util; import javax.servlet.http.HttpServletRequest; +import java.net.InetAddress; +import java.net.UnknownHostException; public class IpUtil { public static String client(HttpServletRequest request) { @@ -10,4 +12,42 @@ public class IpUtil { } return xff; } + + public static String getIpAddr(HttpServletRequest request) { + String ipAddress = null; + try { + ipAddress = request.getHeader("x-forwarded-for"); + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getHeader("WL-Proxy-Client-IP"); + } + if (ipAddress == null || ipAddress.length() == 0 || "unknown".equalsIgnoreCase(ipAddress)) { + ipAddress = request.getRemoteAddr(); + if (ipAddress.equals("127.0.0.1")) { + // 根据网卡取本机配置的IP + InetAddress inet = null; + try { + inet = InetAddress.getLocalHost(); + } catch (UnknownHostException e) { + e.printStackTrace(); + } + ipAddress = inet.getHostAddress(); + } + } + // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + if (ipAddress != null && ipAddress.length() > 15) { // "***.***.***.***".length() + // = 15 + if (ipAddress.indexOf(",") > 0) { + ipAddress = ipAddress.substring(0, ipAddress.indexOf(",")); + } + } + } catch (Exception e) { + ipAddress=""; + } + // ipAddress = this.getRequest().getRemoteAddr(); + + return ipAddress; + } } 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 d6d78032..ab538275 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 @@ -2,24 +2,23 @@ package org.linlinjava.litemall.wx.web; import com.github.binarywang.wxpay.bean.notify.WxPayNotifyResponse; import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyResult; -import com.github.binarywang.wxpay.bean.order.WxPayAppOrderResult; import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult; -import com.github.binarywang.wxpay.bean.request.BaseWxPayRequest; import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest; import com.github.binarywang.wxpay.bean.result.BaseWxPayResult; import com.github.binarywang.wxpay.service.WxPayService; import org.apache.commons.io.IOUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +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.*; import org.linlinjava.litemall.db.util.OrderHandleOption; import org.linlinjava.litemall.db.util.OrderUtil; -import org.linlinjava.litemall.core.util.JacksonUtil; -import org.linlinjava.litemall.core.util.ResponseUtil; import org.linlinjava.litemall.wx.annotation.LoginUser; +import org.linlinjava.litemall.wx.util.IpUtil; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.scheduling.annotation.Scheduled; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; import org.springframework.transaction.TransactionStatus; @@ -290,7 +289,7 @@ public class WxOrderController { // 根据订单商品总价计算运费,满88则免运费,否则8元; BigDecimal freightPrice = new BigDecimal(0.00); if (checkedGoodsPrice.compareTo(new BigDecimal(88.00)) < 0) { - freightPrice = new BigDecimal(8.00); + freightPrice = new BigDecimal(0.00); } // 可以使用的其他钱,例如用户积分 @@ -440,7 +439,7 @@ public class WxOrderController { /** * 付款订单的预支付会话标识 - * + *

* 1. 检测当前订单是否能够付款 * 2. 微信支付平台返回支付订单ID * 3. 设置订单付款状态 @@ -452,8 +451,8 @@ public class WxOrderController { * 失败则 { errno: XXX, errmsg: XXX } */ @PostMapping("prepay") - public Object prepay(@LoginUser Integer userId, @RequestBody String body) { - if(userId == null){ + public Object prepay(@LoginUser Integer userId, @RequestBody String body, HttpServletRequest request) { + if (userId == null) { return ResponseUtil.unlogin(); } Integer orderId = JacksonUtil.parseInteger(body, "orderId"); @@ -477,7 +476,7 @@ public class WxOrderController { LitemallUser user = userService.findById(userId); String openid = user.getWeixinOpenid(); - if(openid == null){ + if (openid == null) { return ResponseUtil.fail(403, "订单不能支付"); } WxPayMpOrderResult result = null; @@ -488,14 +487,14 @@ public class WxOrderController { // TODO 更有意义的显示名称 orderRequest.setBody("litemall小商场-订单测试支付"); // 元转成分 - Integer fee = 1; + Integer fee = 0; // 这里演示仅支付1分 // 实际项目取消下面两行注释 - // BigDecimal actualPrice = order.getActualPrice(); - // fee = actualPrice.multiply(new BigDecimal(100)).intValue(); + BigDecimal actualPrice = order.getActualPrice(); + fee = actualPrice.multiply(new BigDecimal(100)).intValue(); orderRequest.setTotalFee(fee); // TODO 用户IP地址 - orderRequest.setSpbillCreateIp("123.12.12.123"); + orderRequest.setSpbillCreateIp(IpUtil.getIpAddr(request)); result = wxPayService.createOrder(orderRequest); } catch (Exception e) { @@ -518,7 +517,7 @@ public class WxOrderController { * @return 订单操作结果 * 成功则 WxPayNotifyResponse.success的XML内容 * 失败则 WxPayNotifyResponse.fail的XML内容 - * + *

* 注意,这里pay-notify是示例地址,开发者应该设立一个隐蔽的回调地址 */ @PostMapping("pay-notify") @@ -533,19 +532,19 @@ public class WxOrderController { String totalFee = BaseWxPayResult.feeToYuan(result.getTotalFee()); LitemallOrder order = orderService.findBySn(orderSn); - if(order == null){ + if (order == null) { throw new Exception("订单不存在 sn=" + orderSn); } // 检查这个订单是否已经处理过 - if(OrderUtil.isPayStatus(order) && order.getPayId() != null){ + if (OrderUtil.isPayStatus(order) && order.getPayId() != null) { return WxPayNotifyResponse.success("处理成功!"); } // 检查支付订单金额 // TODO 这里1分钱需要改成实际订单金额 - if(!totalFee.equals("0.01")){ - throw new Exception("支付金额不符合 totalFee=" + totalFee); + if (!totalFee.equals(order.getActualPrice().toString())) { + throw new Exception(order.getOrderSn() + " : 支付金额不符合 totalFee=" + totalFee); } order.setPayId(payId); @@ -553,6 +552,9 @@ public class WxOrderController { order.setOrderStatus(OrderUtil.STATUS_PAY); orderService.updateById(order); + //TODO 发送邮件通知,这里最好才用异步发送 + MailUtils.getMailUtils().sendEmail("订单通知", order.toString()); + return WxPayNotifyResponse.success("处理成功!"); } catch (Exception e) { logger.error("微信回调结果异常,异常原因 " + e.getMessage()); @@ -560,7 +562,6 @@ public class WxOrderController { } } - /** * 订单申请退款 * 1. 检测当前订单是否能够退款 From 6ac9478e9cc604559d092baf9d9a7b3dc7aec811 Mon Sep 17 00:00:00 2001 From: Menethil Date: Sat, 14 Jul 2018 19:59:02 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=9F=AD=E4=BF=A1?= =?UTF-8?q?=E9=80=9A=E7=9F=A5=E5=92=8C=E9=82=AE=E4=BB=B6=E9=80=9A=E7=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- litemall-core/pom.xml | 6 +- .../litemall/core/notify/ExecutorConfig.java | 40 ++++++ .../core/notify/LitemallNotifyService.java | 69 +++++++++ .../litemall/core/notify/MailSendService.java | 46 ++++++ .../litemall/core/notify/NotifyUtils.java | 10 ++ .../litemall/core/notify/SMSSendService.java | 64 +++++++++ .../core/notify/WXTemplateMsgSendService.java | 132 ++++++++++++++++++ .../src/main/resources/application.properties | 3 +- .../src/main/resources/notify.properties | 22 +++ .../litemall/wx/web/WxOrderController.java | 14 +- 10 files changed, 399 insertions(+), 7 deletions(-) create mode 100644 litemall-core/src/main/java/org/linlinjava/litemall/core/notify/ExecutorConfig.java create mode 100644 litemall-core/src/main/java/org/linlinjava/litemall/core/notify/LitemallNotifyService.java create mode 100644 litemall-core/src/main/java/org/linlinjava/litemall/core/notify/MailSendService.java create mode 100644 litemall-core/src/main/java/org/linlinjava/litemall/core/notify/NotifyUtils.java create mode 100644 litemall-core/src/main/java/org/linlinjava/litemall/core/notify/SMSSendService.java create mode 100644 litemall-core/src/main/java/org/linlinjava/litemall/core/notify/WXTemplateMsgSendService.java create mode 100644 litemall-core/src/main/resources/notify.properties diff --git a/litemall-core/pom.xml b/litemall-core/pom.xml index aadfb5dc..9855ec35 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 00000000..421a6b1c --- /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 00000000..52de1cef --- /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 00000000..3c8edac7 --- /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 00000000..571d28e9 --- /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 00000000..95f79803 --- /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 00000000..cdaca41f --- /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 257b3064..dd877f46 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 00000000..9579ab7a --- /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 ab538275..ee1cd33e 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 com.github.binarywang.wxpay.service.WxPayService; 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 class WxOrderController { orderRequest.setOutTradeNo(order.getOrderSn()); orderRequest.setOpenid(openid); // TODO 更有意义的显示名称 - orderRequest.setBody("litemall小商场-订单测试支付"); + orderRequest.setBody("订单:" + order.getOrderSn()); // 元转成分 Integer fee = 0; // 这里演示仅支付1分 @@ -552,8 +556,9 @@ public class WxOrderController { 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 class WxOrderController { LitemallOrderGoods orderGoods = orderGoodsList.get(0); return ResponseUtil.ok(orderGoods); } - } \ No newline at end of file