Browse Source

Merge pull request #23 from menethil/master

添加短信通知和邮件通知
linlinjava 7 years ago
parent
commit
03b4860042

+ 15 - 1
litemall-core/pom.xml

@@ -31,10 +31,24 @@
             <groupId>io.springfox</groupId>
             <artifactId>springfox-swagger-ui</artifactId>
         </dependency>
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+            <version>RELEASE</version>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.mail</groupId>
+            <artifactId>javax.mail</artifactId>
+        </dependency>
 
+        <dependency>
+            <groupId>com.github.qcloudsms</groupId>
+            <artifactId>qcloudsms</artifactId>
+            <version>1.0.5</version>
+        </dependency>
     </dependencies>
 
-
     <build>
         <resources>
             <resource>

+ 40 - 0
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;
+    }
+}

+ 69 - 0
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);
+    }
+}

+ 46 - 0
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) {
+
+        }
+    }
+}

+ 10 - 0
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,
+    }
+}

+ 64 - 0
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();
+        }
+    }
+}

+ 132 - 0
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;
+        }
+    }
+}

+ 52 - 0
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;
+        }
+    }
+}

+ 2 - 1
litemall-core/src/main/resources/application.properties

@@ -1 +1,2 @@
-spring.profiles.active=dev
+spring.profiles.active=dev
+spring.message.encoding = UTF-8  

+ 22 - 0
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

+ 5 - 0
litemall-wx-api/pom.xml

@@ -17,6 +17,11 @@
     <dependencies>
 
         <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-mail</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>org.linlinjava</groupId>
             <artifactId>litemall-core</artifactId>
         </dependency>

+ 40 - 0
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;
+    }
 }

+ 27 - 22
litemall-wx-api/src/main/java/org/linlinjava/litemall/wx/web/WxOrderController.java

@@ -2,24 +2,24 @@ 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.notify.LitemallNotifyService;
+import org.linlinjava.litemall.core.notify.NotifyUtils;
+import org.linlinjava.litemall.core.util.JacksonUtil;
+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;
@@ -81,6 +81,9 @@ public class WxOrderController {
     @Autowired
     private WxPayService wxPayService;
 
+    @Autowired
+    private LitemallNotifyService litemallNotifyService;
+
     public WxOrderController() {
     }
 
@@ -290,7 +293,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 +443,7 @@ public class WxOrderController {
 
     /**
      * 付款订单的预支付会话标识
-     *
+     * <p>
      * 1. 检测当前订单是否能够付款
      * 2. 微信支付平台返回支付订单ID
      * 3. 设置订单付款状态
@@ -452,8 +455,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 +480,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;
@@ -486,16 +489,16 @@ public class WxOrderController {
             orderRequest.setOutTradeNo(order.getOrderSn());
             orderRequest.setOpenid(openid);
             // TODO 更有意义的显示名称
-            orderRequest.setBody("litemall小商场-订单测试支付");
+            orderRequest.setBody("订单:" + order.getOrderSn());
             // 元转成分
-            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 +521,7 @@ public class WxOrderController {
      * @return 订单操作结果
      * 成功则 WxPayNotifyResponse.success的XML内容
      * 失败则 WxPayNotifyResponse.fail的XML内容
-     *
+     * <p>
      * 注意,这里pay-notify是示例地址,开发者应该设立一个隐蔽的回调地址
      */
     @PostMapping("pay-notify")
@@ -533,19 +536,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 +556,10 @@ public class WxOrderController {
             order.setOrderStatus(OrderUtil.STATUS_PAY);
             orderService.updateById(order);
 
+            //TODO 发送邮件和短信通知,这里采用异步发送
+            litemallNotifyService.notifyMailMessage("订单通知", order.toString());
+            litemallNotifyService.notifySMSTemplate(order.getMobile(), new String[]{""}, NotifyUtils.NotifyType.PAY_COMPLATED);
+
             return WxPayNotifyResponse.success("处理成功!");
         } catch (Exception e) {
             logger.error("微信回调结果异常,异常原因 " + e.getMessage());
@@ -560,7 +567,6 @@ public class WxOrderController {
         }
     }
 
-
     /**
      * 订单申请退款
      * 1. 检测当前订单是否能够退款
@@ -714,5 +720,4 @@ public class WxOrderController {
         LitemallOrderGoods orderGoods = orderGoodsList.get(0);
         return ResponseUtil.ok(orderGoods);
     }
-
 }