Jelajahi Sumber

fix 多线程下发短信

tjf 3 tahun lalu
induk
melakukan
6482aaa060

+ 45 - 0
boman-web-core/src/main/java/com/boman/web/core/Thread/BranchThreadUtils.java

@@ -0,0 +1,45 @@
+package com.boman.web.core.Thread;
+/**
+ * @author tjf
+ * @Date: 2022/07/13/15:44
+ */
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author tjf
+ * @Date: 2022/07/13/15:44
+ */
+public class BranchThreadUtils {
+    /**
+     * 计算出需要多少个线程
+     *
+     * @param list
+     * @param pageSize
+     * @param <T>
+     * @return
+     */
+    public static <T> List<List<T>> splitList(List<T> list, int pageSize) {
+        int listSize = list.size();
+        int page = (listSize + (pageSize - 1)) / pageSize;
+        List<List<T>> listArray = new ArrayList<List<T>>();
+        for (int i = 0; i < page; i++) {
+            List<T> subList = new ArrayList<T>();
+            for (int j = 0; j < listSize; j++) {
+                //获取当前循环的下标是多少
+                int pageIndex = ((j + 1) + (pageSize - 1)) / pageSize;
+                //判断当前的下标是否是对应线程的取值内
+                if (pageIndex == (i + 1)) {
+                    subList.add(list.get(j));
+                }
+                //判断当前的下标是否是对应线程的最大取值
+                if ((j + 1) == ((i + 1) * pageSize)) {
+                    break;
+                }
+            }
+            listArray.add(subList);
+        }
+        return listArray;
+    }
+}

+ 132 - 0
boman-web-core/src/main/java/com/boman/web/core/Thread/SmsThread.java

@@ -0,0 +1,132 @@
+package com.boman.web.core.Thread;
+/**
+ * @author tjf
+ * @Date: 2022/07/13/15:45
+ */
+
+import com.aliyun.dysmsapi20170525.models.SendBatchSmsRequest;
+import com.aliyun.dysmsapi20170525.models.SendBatchSmsResponse;
+import com.boman.common.core.exception.CustomException;
+import com.boman.common.core.utils.StringUtils;
+import com.boman.web.core.domain.SendSms;
+import com.boman.web.core.utils.SendBatchSmsUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author tjf
+ * @Date: 2022/07/13/15:45
+ */
+public class SmsThread extends Thread {
+    private List<SendSms> smsList;
+
+    public SmsThread(List<SendSms> smsList) {
+        this.smsList = smsList;
+    }
+
+    public List<SendSms> getSmsList() {
+        return smsList;
+    }
+
+    public void setSmsList(List<SendSms> smsList) {
+        this.smsList = smsList;
+    }
+
+    static final String TEMPLATE_CODE = "SMS_245245018";
+    static final String TEMPLATE_CODE_NOTICE = "SMS_245705093";
+
+    /**
+     * 具体发送短信的接口多线程,模板是中考信息修改通知
+     * 如果要发别的模板,需要修改模板名称和增加替换参数
+     */
+    @Override
+    public void run() {
+        if (StringUtils.isNull(smsList) || smsList.size() == 0) {
+            throw new CustomException("导入数据不能为空!");
+        }
+        int maxNums = 100; //每次最多发送100条,我们一次批量发100条
+        int times = 0;// 循环几个100  用List的长度 除 100
+        int size = 0; //
+
+        List<String> phoneList = new ArrayList<>();
+        //List<String> templateList = new ArrayList<>();
+        List<String> signNameList = new ArrayList<>();
+        StringBuffer signNameJson;
+        StringBuffer phoneNumberJson;
+        //StringBuffer templateParamJson;
+        //返回提示
+        String backResult = "";
+        size = smsList.size();
+        if (size < maxNums) {
+            times = 1;
+        } else {
+            times = (size - 1) / maxNums + 1; //为什么要-1 因为如果是200的时候,理论上次数应该是2,而不是3,如果是101,那么次数也是2,这样就保证次数准确。
+        }
+
+        for (int j = 0; j < times; j++) {
+            if (j > 0 && (j * maxNums + 1 > size)) { //边界判定,如果刚好是100条,那么times的值为2,这时候j 为1的时候 101 大于100结束循环,100条以内不生效
+                break;
+            } else {
+                phoneNumberJson = new StringBuffer();
+                signNameJson = new StringBuffer();
+                //templateParamJson = new StringBuffer();
+                phoneNumberJson.append("[");
+                signNameJson.append("[");
+                //templateParamJson.append("[");
+                for (int k = j * maxNums; k < size && k < (j + 1) * maxNums; k++) {
+                    // 防止有空行,手机号是必须要有的
+                    String phone = smsList.get(k).getPhone();
+                    if (StringUtils.isEmpty(phone)) {
+                        continue;
+                    }
+                    phoneNumberJson.append("\"" + smsList.get(k).getPhone() + "\",");
+                    signNameJson.append("\"潜山市数据资源局\",");
+                    //templateParamJson.append("{\"ticketId\":\"" + smsList.get(k).getTicketId() + "\",\"name\":\"" + smsList.get(k).getName() + "\",\"result\":\"" + smsList.get(k).getResult() + "\"},");
+
+                }
+                phoneNumberJson.deleteCharAt(phoneNumberJson.length() - 1);//移除最后一个逗号字符,
+                signNameJson.deleteCharAt(signNameJson.length() - 1);
+                //templateParamJson.deleteCharAt(templateParamJson.length() - 1);//移除最后一个逗号字符
+                phoneNumberJson.append("]");
+                signNameJson.append("]");
+                //templateParamJson.append("]");
+                phoneList.add(phoneNumberJson.toString());
+                signNameList.add(signNameJson.toString());
+                //templateList.add(templateParamJson.toString());
+            }
+            //组装请求对象
+            if (times == phoneList.size()) {
+                for (int i = 0; i < times; i++) {
+                    long startTimeSql = System.currentTimeMillis();
+                    SendBatchSmsRequest sendBatchSmsRequest = new SendBatchSmsRequest();
+                    //组装电话号码
+                    sendBatchSmsRequest.setPhoneNumberJson(phoneList.get(i));
+                    //签名名称
+                    sendBatchSmsRequest.setSignNameJson(signNameList.get(i));
+                    //替换参数
+                    //sendBatchSmsRequest.setTemplateParamJson(templateList.get(i));
+                    //固定的模板名称
+                    sendBatchSmsRequest.setTemplateCode(TEMPLATE_CODE_NOTICE);
+                    long endTimeSql = System.currentTimeMillis() - startTimeSql;
+                    System.out.println("线程" + Thread.currentThread().getId()+"执行批量下发短信通知计算:" + (i+1) + "次,时间" + endTimeSql + "ms");
+                    long startTimeSend = System.currentTimeMillis();
+                    SendBatchSmsResponse sendBatchSmsResponse = SendBatchSmsUtils.sendBatchSms(sendBatchSmsRequest);
+                    long endTimeSend = System.currentTimeMillis() - startTimeSend;
+                    System.out.println("线程" + Thread.currentThread().getId()+"执行批量下发短信通知接口请求:" + (i+1) + "次,时间"+ endTimeSend + "ms");
+                    if (sendBatchSmsResponse != null) {
+                        String code = sendBatchSmsResponse.getBody().getCode();
+                        if (sendBatchSmsResponse.getBody().getCode() != null && "OK".equals(code)) {
+                            //批量请求发送短信成功
+                            System.out.println("批量短信发送成功:" + phoneList.get(i).split(",").length + "条");
+                            backResult = backResult + "第" + i + "次批量成功  ";
+                        } else {
+                            System.out.println("批量短信发送失败!");
+                            backResult = backResult + "第" + i + "次批量失败  ";
+                        }
+                    }
+                }
+            }
+        }
+    }
+}

+ 42 - 1
boman-web-core/src/main/java/com/boman/web/core/controller/SendSmsController.java

@@ -26,7 +26,7 @@ import org.springframework.web.multipart.MultipartFile;
 
 /**
  * 中考下发短信日志Controller
- * 
+ *
  * @author boman
  * @date 2022-07-11
  */
@@ -106,6 +106,26 @@ public class SendSmsController extends BaseController
         return AjaxResult.success(message);
     }
 
+    /**
+     * 导入发送短信的中考信息修改通知数据
+     * @param file
+     * @param updateSupport
+     * @return
+     * @throws Exception
+     */
+    @PostMapping("/importDataNotice")
+    public AjaxResult importDataNotice(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        long startTimeSql = System.currentTimeMillis();
+        ExcelUtil<SendSms> util = new ExcelUtil<SendSms>(SendSms.class);
+        List<SendSms> userList = util.importExcel(file.getInputStream());
+        String operName = SecurityUtils.getUsername();
+        String message = sendSmsService.importUserNotice(userList, updateSupport, operName);
+        long endTimeSql = System.currentTimeMillis() - startTimeSql;
+        System.out.println("执行批量下发通知短信模板共:" + endTimeSql + "ms");
+        return AjaxResult.success(message);
+    }
+
     /**
      * 单独发送短信的接口
      */
@@ -139,4 +159,25 @@ public class SendSmsController extends BaseController
         }
         return AjaxResult.error("发送失败");
     }
+
+    /**
+     * 导入发送短信的中考信息修改通知数据多线程
+     * @param file
+     * @param updateSupport
+     * @return
+     * @throws Exception
+     */
+    @PostMapping("/importDataNoticeMore")
+    public AjaxResult importDataNoticeMore(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        long startTimeSql = System.currentTimeMillis();
+        ExcelUtil<SendSms> util = new ExcelUtil<SendSms>(SendSms.class);
+        List<SendSms> userList = util.importExcel(file.getInputStream());
+        String operName = SecurityUtils.getUsername();
+        String message = sendSmsService.importUserNoticeMore(userList, updateSupport, operName);
+        long endTimeSql = System.currentTimeMillis() - startTimeSql;
+        System.out.println("执行批量下发通知短信模板共:" + endTimeSql + "ms");
+        return AjaxResult.success(message);
+    }
+
 }

+ 19 - 1
boman-web-core/src/main/java/com/boman/web/core/service/sendSms/ISendSmsService.java

@@ -60,7 +60,7 @@ public interface ISendSmsService
     public int deleteSendSmsById(String id);
 
     /**
-     * 导入用户数据
+     * 导入下发中考录取信息
      *
      * @param smsList 数据列表
      * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
@@ -68,4 +68,22 @@ public interface ISendSmsService
      * @return 结果
      */
     public String importUser(List<SendSms> smsList, Boolean isUpdateSupport, String operName);
+
+    /**
+     * 导入下发中考身份信息修改通知
+     * @param smsList
+     * @param isUpdateSupport
+     * @param operName
+     * @return
+     */
+    public String importUserNotice(List<SendSms> smsList, Boolean isUpdateSupport, String operName);
+
+    /**
+     * 导入下发中考身份信息修改通知多线程
+     * @param smsList
+     * @param isUpdateSupport
+     * @param operName
+     * @return
+     */
+    public String importUserNoticeMore(List<SendSms> smsList, Boolean isUpdateSupport, String operName);
 }

+ 124 - 7
boman-web-core/src/main/java/com/boman/web/core/service/sendSms/Impl/SendSmsServiceImpl.java

@@ -5,16 +5,13 @@ import java.util.List;
 
 import com.aliyun.dysmsapi20170525.models.SendBatchSmsRequest;
 import com.aliyun.dysmsapi20170525.models.SendBatchSmsResponse;
-import com.aliyuncs.dysmsapi.model.v20170525.QuerySendDetailsResponse;
-import com.aliyuncs.exceptions.ClientException;
 import com.boman.common.core.exception.CustomException;
 import com.boman.common.core.utils.DateUtils;
 import com.boman.common.core.utils.StringUtils;
-import com.boman.domain.dto.AjaxResult;
+import com.boman.web.core.Thread.BranchThreadUtils;
 import com.boman.web.core.service.sendSms.ISendSmsService;
+import com.boman.web.core.Thread.SmsThread;
 import com.boman.web.core.utils.SendBatchSmsUtils;
-import com.boman.web.core.utils.SendSmsUtils;
-import org.checkerframework.checker.units.qual.A;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import com.boman.web.core.mapper.SendSmsMapper;
@@ -35,6 +32,7 @@ public class SendSmsServiceImpl implements ISendSmsService {
      * todo 短信模板名称,需要替换
      */
     static final String TEMPLATE_CODE = "SMS_245245018";
+    static final String TEMPLATE_CODE_NOTICE = "SMS_245705093";
 
     /**
      * 查询中考下发短信日志
@@ -118,7 +116,7 @@ public class SendSmsServiceImpl implements ISendSmsService {
         if (StringUtils.isNull(smsList) || smsList.size() == 0) {
             throw new CustomException("导入数据不能为空!");
         }
-        int maxNums = 2; //每次最多发送100条,我们一次批量发100条
+        int maxNums = 100; //每次最多发送100条,我们一次批量发100条
         int times = 0;// 循环几个100  用List的长度 除 100
         int size = 0; //
 
@@ -131,7 +129,7 @@ public class SendSmsServiceImpl implements ISendSmsService {
         //返回提示
         String backResult = "";
         size = smsList.size();
-        if (size < 2) {
+        if (size < 100) {
             times = 1;
         } else {
             times = (size - 1) / maxNums + 1; //为什么要-1 因为如果是200的时候,理论上次数应该是2,而不是3,如果是101,那么次数也是2,这样就保证次数准确。
@@ -211,4 +209,123 @@ public class SendSmsServiceImpl implements ISendSmsService {
         }
         return backResult;
     }
+
+    /**
+     * 导入下发中考身份信息修改通知
+     * @param smsList
+     * @param isUpdateSupport
+     * @param operName
+     * @return
+     */
+    @Override
+    public String importUserNotice(List<SendSms> smsList, Boolean isUpdateSupport, String operName) {
+        if (StringUtils.isNull(smsList) || smsList.size() == 0) {
+            throw new CustomException("导入数据不能为空!");
+        }
+        int maxNums = 100; //每次最多发送100条,我们一次批量发100条
+        int times = 0;// 循环几个100  用List的长度 除 100
+        int size = 0; //
+
+        List<String> phoneList = new ArrayList<>();
+        List<String> signNameList = new ArrayList<>();
+        StringBuffer signNameJson;
+        StringBuffer phoneNumberJson;
+        //返回提示
+        String backResult = "";
+        size = smsList.size();
+        if (size < 100) {
+            times = 1;
+        } else {
+            times = (size - 1) / maxNums + 1; //为什么要-1 因为如果是200的时候,理论上次数应该是2,而不是3,如果是101,那么次数也是2,这样就保证次数准确。
+        }
+
+        for (int j = 0; j < times; j++) {
+            if (j > 0 && (j * maxNums + 1 > size)) { //边界判定,如果刚好是100条,那么times的值为2,这时候j 为1的时候 101 大于100结束循环,100条以内不生效
+                break;
+            } else {
+                phoneNumberJson = new StringBuffer();
+                signNameJson = new StringBuffer();
+                phoneNumberJson.append("[");
+                signNameJson.append("[");
+                for (int k = j * maxNums; k < size && k < (j + 1) * maxNums; k++) {
+                    // 防止有空行,手机号是必须要有的
+                    String phone = smsList.get(k).getPhone();
+                    if (StringUtils.isEmpty(phone)) {
+                        continue;
+                    }
+                    phoneNumberJson.append("\"" + smsList.get(k).getPhone() + "\",");
+                    signNameJson.append("\"潜山市数据资源局\",");
+                }
+                phoneNumberJson.deleteCharAt(phoneNumberJson.length() - 1);//移除最后一个逗号字符,
+                signNameJson.deleteCharAt(signNameJson.length() - 1);
+                phoneNumberJson.append("]");
+                signNameJson.append("]");
+                phoneList.add(phoneNumberJson.toString());
+                signNameList.add(signNameJson.toString());
+            }
+            //组装请求对象
+            if (times == phoneList.size()) {
+                for (int i = 0; i < times; i++) {
+                    long startTimeSql = System.currentTimeMillis();
+                    SendBatchSmsRequest sendBatchSmsRequest = new SendBatchSmsRequest();
+                    //组装电话号码
+                    sendBatchSmsRequest.setPhoneNumberJson(phoneList.get(i));
+                    //签名名称
+                    sendBatchSmsRequest.setSignNameJson(signNameList.get(i));
+                    //固定的模板名称
+                    sendBatchSmsRequest.setTemplateCode(TEMPLATE_CODE_NOTICE);
+                    long endTimeSql = System.currentTimeMillis() - startTimeSql;
+                    System.out.println("执行批量下发短信通知计算:"+i+"次,时间" + endTimeSql + "ms");
+                    long startTimeSend = System.currentTimeMillis();
+                    SendBatchSmsResponse sendBatchSmsResponse = SendBatchSmsUtils.sendBatchSms(sendBatchSmsRequest);
+                    long endTimeSend = System.currentTimeMillis() - startTimeSend;
+                    System.out.println("执行批量下发短信通知接口请求:" + endTimeSend + "ms");
+                    SendSms sendSms = new SendSms();
+                    if (sendBatchSmsResponse != null) {
+                        String code = sendBatchSmsResponse.getBody().getCode();
+                        if (sendBatchSmsResponse.getBody().getCode() != null && "OK".equals(code)) {
+                            sendSms.setStatus("发送成功");
+                            sendSms.setPhone(String.join(",", phoneList));
+                            sendSms.setCreateBy(operName);
+                            sendSmsMapper.insertSendSms(sendSms);
+                            //批量请求发送短信成功
+                            System.out.println("批量短信发送成功:" + phoneList.get(i).split(",").length + "条");
+                            backResult = backResult +"第"+i+"次批量成功  ";
+                        } else {
+                            sendSms.setPhone(String.join(",", phoneList));
+                            sendSms.setStatus("发送失败");
+                            sendSms.setCreateBy(operName);
+                            sendSmsMapper.insertSendSms(sendSms);
+                            System.out.println("批量短信发送失败!");
+                            backResult = backResult +"第"+i+"次批量失败  ";
+                        }
+                    }
+                }
+            }
+        }
+        return backResult;
+    }
+
+    /**
+     * 导入下发中考身份信息修改通知 多线程
+     * @param smsList
+     * @param isUpdateSupport
+     * @param operName
+     * @return
+     */
+    @Override
+    public String importUserNoticeMore(List<SendSms> smsList, Boolean isUpdateSupport, String operName) {
+        //定义每个线程处理多少用户
+        Integer count = 650;
+        //根据用户数确定需要多少个线程
+        List<List<SendSms>> lists = BranchThreadUtils.splitList(smsList, count);
+        //将用户传每个线程执行
+        for (List<SendSms> list : lists) {
+            SmsThread smsThread = new SmsThread(list);
+            //启动线程
+            smsThread.start();
+            System.out.println("线程" + Thread.currentThread().getId()+"启动");
+        }
+        return "发送成功";
+    }
 }