| @@ -1,9 +1,9 @@ | |||||
| package com.github.niefy.common.utils; | package com.github.niefy.common.utils; | ||||
| import com.alibaba.fastjson.JSONObject; | import com.alibaba.fastjson.JSONObject; | ||||
| import com.aliyuncs.CommonRequest; | import com.aliyuncs.CommonRequest; | ||||
| import com.aliyuncs.CommonResponse; | import com.aliyuncs.CommonResponse; | ||||
| import com.aliyuncs.DefaultAcsClient; | import com.aliyuncs.DefaultAcsClient; | ||||
| import com.aliyuncs.IAcsClient; | |||||
| import com.aliyuncs.exceptions.ClientException; | import com.aliyuncs.exceptions.ClientException; | ||||
| import com.aliyuncs.exceptions.ServerException; | import com.aliyuncs.exceptions.ServerException; | ||||
| import com.aliyuncs.http.MethodType; | import com.aliyuncs.http.MethodType; | ||||
| @@ -14,18 +14,18 @@ import org.springframework.stereotype.Component; | |||||
| @Component | @Component | ||||
| public class SmsUtils { | public class SmsUtils { | ||||
| @Value("${sms.accessKeyId}") | @Value("${sms.accessKeyId}") | ||||
| public static String accessKeyId; | |||||
| public String accessKeyId; | |||||
| @Value("${sms.secret}") | @Value("${sms.secret}") | ||||
| public static String secret; | |||||
| public String secret; | |||||
| @Value("${sms.signName}") | @Value("${sms.signName}") | ||||
| public static String signName; // 短信签名 | |||||
| public String signName; // 短信签名 | |||||
| @Value("${sms.templateCode}") | @Value("${sms.templateCode}") | ||||
| public static String templateCode; //短信模板 | |||||
| public String templateCode; //短信模板 | |||||
| @Value("${sms.regionId}") | @Value("${sms.regionId}") | ||||
| public static String regionId; // 短信服务器区域 | |||||
| public String regionId; // 短信服务器区域 | |||||
| //平台信息 | //平台信息 | ||||
| public static String sendNoteMessgae(String phoneNumbers, String code) { | |||||
| DefaultProfile profile = DefaultProfile.getProfile("cn-hangzhou", accessKeyId, secret); | |||||
| public String sendNoteMessgae(String phoneNumbers, String code) { | |||||
| DefaultProfile profile = DefaultProfile.getProfile(regionId, accessKeyId, secret); | |||||
| DefaultAcsClient client = new DefaultAcsClient(profile); | DefaultAcsClient client = new DefaultAcsClient(profile); | ||||
| CommonRequest request = new CommonRequest(); | CommonRequest request = new CommonRequest(); | ||||
| @@ -33,7 +33,6 @@ public class SmsUtils { | |||||
| //下面两个不能动 | //下面两个不能动 | ||||
| request.setSysProduct("Dysmsapi"); | request.setSysProduct("Dysmsapi"); | ||||
| request.setSysDomain("dysmsapi.aliyuncs.com"); | request.setSysDomain("dysmsapi.aliyuncs.com"); | ||||
| request.setSysVersion("2017-05-25"); | request.setSysVersion("2017-05-25"); | ||||
| request.setSysAction("SendSms"); | request.setSysAction("SendSms"); | ||||
| //自定义参数(手机号,验证码,签名,模板) | //自定义参数(手机号,验证码,签名,模板) | ||||
| @@ -44,6 +44,7 @@ public class ShiroConfig { | |||||
| filterMap.put("/sys/login", "anon"); | filterMap.put("/sys/login", "anon"); | ||||
| filterMap.put("/sms/**", "anon");//短信相关 | filterMap.put("/sms/**", "anon");//短信相关 | ||||
| filterMap.put("/manage/wxUser/findByPhone/**", "anon"); | filterMap.put("/manage/wxUser/findByPhone/**", "anon"); | ||||
| filterMap.put("/manage/templateMsg/sendTemplateMsg/**", "anon"); // 消息推送接口 | |||||
| filterMap.put("/sys/**", "oauth2"); | filterMap.put("/sys/**", "oauth2"); | ||||
| filterMap.put("/manage/**", "oauth2"); | filterMap.put("/manage/**", "oauth2"); | ||||
| filterMap.put("/wx/**", "anon"); | filterMap.put("/wx/**", "anon"); | ||||
| @@ -1,6 +1,7 @@ | |||||
| package com.github.niefy.modules.wx.manage; | package com.github.niefy.modules.wx.manage; | ||||
| import com.github.niefy.common.utils.R; | import com.github.niefy.common.utils.R; | ||||
| import com.github.niefy.common.utils.SmsUtils; | |||||
| import com.github.niefy.common.utils.StringUtils; | import com.github.niefy.common.utils.StringUtils; | ||||
| import com.github.niefy.modules.wx.entity.SMS; | import com.github.niefy.modules.wx.entity.SMS; | ||||
| import com.github.niefy.modules.wx.entity.WxUser; | import com.github.niefy.modules.wx.entity.WxUser; | ||||
| @@ -24,6 +25,8 @@ public class SmsController { | |||||
| @Autowired | @Autowired | ||||
| private WxUserService userService; | private WxUserService userService; | ||||
| @Autowired | |||||
| private SmsUtils smsUtils; | |||||
| @PostMapping(value = "/code") | @PostMapping(value = "/code") | ||||
| @ApiOperation(value = "获取短信验证码", notes = "获取短信验证码") | @ApiOperation(value = "获取短信验证码", notes = "获取短信验证码") | ||||
| @@ -35,13 +38,13 @@ public class SmsController { | |||||
| } | } | ||||
| Random random = new Random(); | Random random = new Random(); | ||||
| StringBuffer smscode = new StringBuffer(); | StringBuffer smscode = new StringBuffer(); | ||||
| smscode.append("123456"); | |||||
| // for (int i = 0; i < 6; i++) { | |||||
| // smscode.append(random.nextInt(10)); | |||||
| // } | |||||
| // smscode.append("123456"); | |||||
| for (int i = 0; i < 6; i++) { | |||||
| smscode.append(random.nextInt(10)); | |||||
| } | |||||
| //发送短信 | //发送短信 | ||||
| // String code = SmsUtils.sendNoteMessgae(mobile, String.valueOf(smscode)); | |||||
| String code = "OK"; | |||||
| String code = smsUtils.sendNoteMessgae(mobile, String.valueOf(smscode)); | |||||
| // String code = "OK"; | |||||
| if ("OK".equals(code)) { | if ("OK".equals(code)) { | ||||
| //返回验证码和发送时间 | //返回验证码和发送时间 | ||||
| return R.ok().put("smsCode", String.valueOf(smscode) + new Date().getTime()); | return R.ok().put("smsCode", String.valueOf(smscode) + new Date().getTime()); | ||||
| @@ -1,30 +1,22 @@ | |||||
| package com.github.niefy.modules.wx.manage; | package com.github.niefy.modules.wx.manage; | ||||
| import com.alibaba.fastjson.JSONObject; | |||||
| import com.github.niefy.common.utils.PageUtils; | |||||
| import com.github.niefy.common.utils.R; | |||||
| import com.github.niefy.common.utils.StringUtils; | import com.github.niefy.common.utils.StringUtils; | ||||
| import com.github.niefy.config.TaskExcutor; | import com.github.niefy.config.TaskExcutor; | ||||
| import com.github.niefy.modules.wx.entity.TemplateMsgLog; | |||||
| import com.github.niefy.modules.wx.entity.WxUser; | import com.github.niefy.modules.wx.entity.WxUser; | ||||
| import com.github.niefy.modules.wx.service.TemplateMsgLogService; | |||||
| import com.github.niefy.modules.wx.service.TemplateMsgService; | import com.github.niefy.modules.wx.service.TemplateMsgService; | ||||
| import com.github.niefy.modules.wx.service.WxUserService; | import com.github.niefy.modules.wx.service.WxUserService; | ||||
| import io.swagger.annotations.Api; | import io.swagger.annotations.Api; | ||||
| import io.swagger.annotations.ApiOperation; | import io.swagger.annotations.ApiOperation; | ||||
| import me.chanjar.weixin.mp.api.WxMpService; | |||||
| import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; | import me.chanjar.weixin.mp.bean.template.WxMpTemplateData; | ||||
| import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; | import me.chanjar.weixin.mp.bean.template.WxMpTemplateMessage; | ||||
| import me.chanjar.weixin.mp.enums.WxMpApiUrl; | |||||
| import me.chanjar.weixin.mp.util.WxMpConfigStorageHolder; | |||||
| import org.apache.shiro.authz.annotation.RequiresPermissions; | |||||
| import org.springframework.beans.factory.annotation.Autowired; | import org.springframework.beans.factory.annotation.Autowired; | ||||
| import org.springframework.web.bind.annotation.*; | |||||
| import org.springframework.web.bind.annotation.PostMapping; | |||||
| import org.springframework.web.bind.annotation.RequestMapping; | |||||
| import org.springframework.web.bind.annotation.RequestParam; | |||||
| import org.springframework.web.bind.annotation.RestController; | |||||
| import java.util.ArrayList; | import java.util.ArrayList; | ||||
| import java.util.Arrays; | |||||
| import java.util.List; | import java.util.List; | ||||
| import java.util.Map; | |||||
| /** | /** | ||||
| @@ -51,35 +43,29 @@ public class TemplateMsgManageController { | |||||
| * eg:{"phones":"18811408841,18811408841","datas":"dept-威海市乳山市|dept-威海市乳山市","appid":"公众号appid","templateId":"模板IDtemplateId","url":"url"} | * eg:{"phones":"18811408841,18811408841","datas":"dept-威海市乳山市|dept-威海市乳山市","appid":"公众号appid","templateId":"模板IDtemplateId","url":"url"} | ||||
| * 使用固定线程的线程池 | * 使用固定线程的线程池 | ||||
| */ | */ | ||||
| @GetMapping("/sendTemplateMsg/{templateMsg}") | |||||
| @PostMapping("/sendTemplateMsg") | |||||
| @ApiOperation(value = "外部接口-发送模板信息") | @ApiOperation(value = "外部接口-发送模板信息") | ||||
| public void sendTemplateMsg(@PathVariable("templateMsg") String templateMsg) { | |||||
| TaskExcutor.submit(() -> { | |||||
| JSONObject templateMsgObject = JSONObject.parseObject(templateMsg); | |||||
| String phones = templateMsgObject.getString("phones");//所有手机号 | |||||
| String phoness[] = phones.split(","); | |||||
| for (String phone:phoness) { | |||||
| WxUser wxUser = userService.findByPhone(phone); | |||||
| if(StringUtils.isNotNull(wxUser)){ | |||||
| String datas = templateMsgObject.getString("datas");//所有模板内容 | |||||
| String appid = templateMsgObject.getString("appid"); | |||||
| String templateId = templateMsgObject.getString("templateId"); | |||||
| String url = templateMsgObject.getString("url"); | |||||
| String datass[] = datas.split("\\|"); | |||||
| List<WxMpTemplateData> data = new ArrayList<>(); | |||||
| for (String data_z:datass) { | |||||
| String data_zz[] = data_z.split("-"); | |||||
| data.add(new WxMpTemplateData(data_zz[0], data_zz[1])); | |||||
| } | |||||
| WxMpTemplateMessage wxMpTemplateMessage = WxMpTemplateMessage.builder() | |||||
| .templateId(templateId) | |||||
| .url(url) | |||||
| .toUser(wxUser.getOpenid()) | |||||
| .data(data) | |||||
| .build(); | |||||
| templateMsgService.sendTemplateMsg(wxMpTemplateMessage,appid); | |||||
| public void sendTemplateMsg(@RequestParam("phones") String phones, @RequestParam("datas") String datas, | |||||
| @RequestParam("appid") String appid, @RequestParam("templateId") String templateId, | |||||
| @RequestParam("url") String url) { | |||||
| String phoness[] = phones.split(","); | |||||
| for (String phone : phoness) { | |||||
| WxUser wxUser = userService.findByPhone(phone); | |||||
| if (StringUtils.isNotNull(wxUser)) { | |||||
| String datass[] = datas.split(","); | |||||
| List<WxMpTemplateData> data = new ArrayList<>(); | |||||
| for (String data_z : datass) { | |||||
| String data_zz[] = data_z.split("-"); | |||||
| data.add(new WxMpTemplateData(data_zz[0], data_zz[1])); | |||||
| } | } | ||||
| WxMpTemplateMessage wxMpTemplateMessage = WxMpTemplateMessage.builder() | |||||
| .templateId(templateId) | |||||
| .url(url) | |||||
| .toUser(wxUser.getOpenid()) | |||||
| .data(data) | |||||
| .build(); | |||||
| templateMsgService.sendTemplateMsg(wxMpTemplateMessage, appid); | |||||
| } | } | ||||
| }); | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| @@ -36,59 +36,59 @@ public class TemplateMsgServiceImpl implements TemplateMsgService { | |||||
| @Autowired | @Autowired | ||||
| MsgTemplateService msgTemplateService; | MsgTemplateService msgTemplateService; | ||||
| @Autowired | @Autowired | ||||
| WxUserService wxUserService; | |||||
| WxUserService wxUserService; | |||||
| /** | /** | ||||
| * 发送微信模版消息,使用固定线程的线程池 | * 发送微信模版消息,使用固定线程的线程池 | ||||
| */ | */ | ||||
| @Override | @Override | ||||
| @Async | @Async | ||||
| public void sendTemplateMsg(WxMpTemplateMessage msg,String appid) { | |||||
| TaskExcutor.submit(() -> { | |||||
| String result; | |||||
| try { | |||||
| wxService.switchover(appid); | |||||
| result = wxService.getTemplateMsgService().sendTemplateMsg(msg); | |||||
| } catch (WxErrorException e) { | |||||
| result = e.getMessage(); | |||||
| } | |||||
| public void sendTemplateMsg(WxMpTemplateMessage msg, String appid) { | |||||
| // TaskExcutor.submit(() -> { | |||||
| String result; | |||||
| try { | |||||
| wxService.switchover(appid); | |||||
| result = wxService.getTemplateMsgService().sendTemplateMsg(msg); | |||||
| } catch (WxErrorException e) { | |||||
| result = e.getMessage(); | |||||
| } | |||||
| //保存发送日志 | |||||
| TemplateMsgLog log = new TemplateMsgLog(msg,appid, result); | |||||
| templateMsgLogService.addLog(log); | |||||
| }); | |||||
| //保存发送日志 | |||||
| TemplateMsgLog log = new TemplateMsgLog(msg, appid, result); | |||||
| templateMsgLogService.addLog(log); | |||||
| // }); | |||||
| } | } | ||||
| @Override | @Override | ||||
| @Async | |||||
| @Async | |||||
| public void sendMsgBatch(TemplateMsgBatchForm form, String appid) { | public void sendMsgBatch(TemplateMsgBatchForm form, String appid) { | ||||
| logger.info("批量发送模板消息任务开始,参数:{}",form.toString()); | |||||
| logger.info("批量发送模板消息任务开始,参数:{}", form.toString()); | |||||
| wxService.switchover(appid); | wxService.switchover(appid); | ||||
| WxMpTemplateMessage.WxMpTemplateMessageBuilder builder = WxMpTemplateMessage.builder() | |||||
| .templateId(form.getTemplateId()) | |||||
| .url(form.getUrl()) | |||||
| .miniProgram(form.getMiniprogram()) | |||||
| .data(form.getData()); | |||||
| Map<String, Object> filterParams = form.getWxUserFilterParams(); | |||||
| if(filterParams==null) { | |||||
| filterParams=new HashMap<>(8); | |||||
| WxMpTemplateMessage.WxMpTemplateMessageBuilder builder = WxMpTemplateMessage.builder() | |||||
| .templateId(form.getTemplateId()) | |||||
| .url(form.getUrl()) | |||||
| .miniProgram(form.getMiniprogram()) | |||||
| .data(form.getData()); | |||||
| Map<String, Object> filterParams = form.getWxUserFilterParams(); | |||||
| if (filterParams == null) { | |||||
| filterParams = new HashMap<>(8); | |||||
| } | } | ||||
| long currentPage=1L,totalPages=Long.MAX_VALUE; | |||||
| filterParams.put("appid",appid); | |||||
| filterParams.put("limit","500"); | |||||
| while (currentPage<=totalPages){ | |||||
| filterParams.put("page",String.valueOf(currentPage)); | |||||
| long currentPage = 1L, totalPages = Long.MAX_VALUE; | |||||
| filterParams.put("appid", appid); | |||||
| filterParams.put("limit", "500"); | |||||
| while (currentPage <= totalPages) { | |||||
| filterParams.put("page", String.valueOf(currentPage)); | |||||
| //按条件查询用户 | //按条件查询用户 | ||||
| IPage<WxUser> wxUsers = wxUserService.queryPage(filterParams); | |||||
| logger.info("批量发送模板消息任务,使用查询条件,处理第{}页,总用户数:{}",currentPage,wxUsers.getTotal()); | |||||
| wxUsers.getRecords().forEach(user->{ | |||||
| WxMpTemplateMessage msg = builder.toUser(user.getOpenid()).build(); | |||||
| this.sendTemplateMsg(msg,appid); | |||||
| }); | |||||
| currentPage=wxUsers.getCurrent()+1L; | |||||
| totalPages=wxUsers.getPages(); | |||||
| } | |||||
| logger.info("批量发送模板消息任务结束"); | |||||
| IPage<WxUser> wxUsers = wxUserService.queryPage(filterParams); | |||||
| logger.info("批量发送模板消息任务,使用查询条件,处理第{}页,总用户数:{}", currentPage, wxUsers.getTotal()); | |||||
| wxUsers.getRecords().forEach(user -> { | |||||
| WxMpTemplateMessage msg = builder.toUser(user.getOpenid()).build(); | |||||
| this.sendTemplateMsg(msg, appid); | |||||
| }); | |||||
| currentPage = wxUsers.getCurrent() + 1L; | |||||
| totalPages = wxUsers.getPages(); | |||||
| } | |||||
| logger.info("批量发送模板消息任务结束"); | |||||
| } | } | ||||
| } | } | ||||
| @@ -1,7 +1,7 @@ | |||||
| spring: | spring: | ||||
| datasource: | datasource: | ||||
| driver-class-name: com.mysql.cj.jdbc.Driver | driver-class-name: com.mysql.cj.jdbc.Driver | ||||
| url: jdbc:mysql://${MYSQL_IP:localhost}:${MYSQL_PORT:3318}/wx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai | |||||
| url: jdbc:mysql://${MYSQL_IP:116.255.223.226}:${MYSQL_PORT:3318}/wx?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai | |||||
| username: ${MYSQL_USERNAME:gly} | username: ${MYSQL_USERNAME:gly} | ||||
| password: ${MYSQL_PASSWORD:glyadmin} | password: ${MYSQL_PASSWORD:glyadmin} | ||||
| @@ -4,7 +4,7 @@ server: | |||||
| uri-encoding: UTF-8 | uri-encoding: UTF-8 | ||||
| max-threads: 1000 | max-threads: 1000 | ||||
| min-spare-threads: 30 | min-spare-threads: 30 | ||||
| port: ${SERVER_PORT:8088} | |||||
| port: ${SERVER_PORT:9090} | |||||
| connection-timeout: 5000ms | connection-timeout: 5000ms | ||||
| servlet: | servlet: | ||||
| context-path: /wx | context-path: /wx | ||||
| @@ -71,4 +71,12 @@ wx: | |||||
| task: | task: | ||||
| corePoolSize: 5 #核心线程数 | corePoolSize: 5 #核心线程数 | ||||
| maximumPoolSize: 30 #最大线程数 | maximumPoolSize: 30 #最大线程数 | ||||
| keepAliveTime: 60 #线程最大空闲时间 | |||||
| keepAliveTime: 60 #线程最大空闲时间 | |||||
| sms: | |||||
| # 短信平台 | |||||
| accessKeyId: LTAI5tM4VsSNgjUZCcDwxRPZ | |||||
| secret: IFmNCBE8IeAS8I8NiIxGjxpD3DrKCR | |||||
| signName: 农燊高科 | |||||
| templateCode: SMS_218160192 | |||||
| regionId: cn-hangzhou | |||||