/**
* 推送消息 APP、短信
* @param message
* @throws Exception
*/
public void sendMsg(Message message) throws Exception{
try {
logger.info("send message start...");
long startTime = System.currentTimeMillis();
BlockingQueue<Runnable> queue = new LinkedBlockingQueue<Runnable>(20000);
ThreadPoolExecutor executors = new ThreadPoolExecutor(5, 6, 60000, TimeUnit.SECONDS, queue);
//要推送的用户总数
int count = filterPhonesCount(message);
logger.info("message all count=>{}",count);
//初始每个线程处理的用户数量
final int eveLength = 2000;
//计算处理所有用户需要的线程数量
int eveBlocks = count / eveLength + (count % eveLength != 0 ? 1 : 0);
logger.info("need thread's count=>{}",eveBlocks);
//线程计数器
CountDownLatch doneSignal = new CountDownLatch(eveBlocks);
//开启线程处理
int doneCount = 0;
for (int page = 0; page < eveBlocks; page++) { /* blocks太大可以再细分重新调度 */
MessageSendThread ms = new MessageSendThread(messageDao,message,page + 1,eveLength,doneSignal);
executors.execute(ms);
//logger.info("start thread =>{}",page+1);
doneCount++;
}
doneSignal.await();//等待所有计数器线程执行完
long endTime = System.currentTimeMillis();
logger.info("send message all thread ends!time(s)=>{}",(startTime-endTime)/1000);
logger.info("all thread count=>{}",doneCount);
} catch (Exception e) {
logger.error("send message error=>{}",e);
}
}
package com.bankhui.center.business.service.message;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.http.impl.cookie.DateUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.bankhui.center.business.dao.message.MessageDao;
import com.bankhui.center.business.entity.message.Message;
import com.bankhui.center.common.utils.DateUtil;
import com.bankhui.center.common.utils.SmsUtils;
import com.bankhui.center.jpush.JPushClient;
import com.bankhui.center.jpush.JPushScheduleClient;
/**
* 系统消息推送线程(处理 block数据块)
*/
public class MessageSendThread implements Runnable{
private final Logger logger = LoggerFactory.getLogger(MessageSendThread.class);
private Integer currentIndex;//当前索引
private Integer rows;//处理数据条数
private CountDownLatch doneSignal;//处理线程条数
private Message message;//消息实体
private MessageDao messageDao;//DAO
public MessageSendThread(MessageDao messageDao,Message message,Integer currentIndex,Integer rows, CountDownLatch doneSignal) {
this.message = message;
this.messageDao = messageDao;
this.currentIndex = currentIndex;
this.rows = rows;
this.doneSignal = doneSignal;
}
@Override
public void run() {
try {
/**
* ---------1.查询当前的block范围内的发送的手机号=>筛选目标客户群手机号---------
*/
Map<String,Object> smsDataMap = filterPhones(message,currentIndex,rows);
if(MapUtils.isEmpty(smsDataMap)|| null == smsDataMap.get("jgAlias")
||StringUtils.isBlank(smsDataMap.get("jgAlias").toString())){
logger.debug("push param is null,caurse by target customers is nothing");
throw new RuntimeException();
}
logger.info("type of target customers=>{}", message.getReceiverGroupType());
logger.info(" result of filter target customers=>{}", smsDataMap);
/**
* ---------2.批量发送消息---------
* TODO://((-?)\d{1,11}\,?){1,n} n个线程分批发送
*/
if("0".equals(message.getType())){//短信发送
sendBatch(smsDataMap.get("phone").toString(),message);
}
if("1".equals(message.getType())){//APP推送
if("0".equals(message.getMethod())){//实时发送
sendNormal(smsDataMap);
}
if("1".equals(message.getMethod())){//定时发送
sendDelay(smsDataMap);
}
}
} catch (Exception e) {
logger.error("send message thread exception=>{}{}{}{}",message,currentIndex,rows,e);
}finally{
doneSignal.countDown();//工人完成工作,计数器减一
}
}
/**
* APP实时推送
* @param smsDataMap
*/
private void sendNormal(Map<String,Object> smsDataMap) {
//0为全部发送
if("0".equals(message.getReceiverGroupType())){
JPushClient.appSendAll(message.getTitle(), message.getContent(), message.getId().toString(), StringUtils.isBlank(message.getLink())?"0":"1", message.getLink());
}else{
String[] jgAlias = smsDataMap.get("jgAlias").toString().split(",");
for(String jgAlia:jgAlias){
JPushClient.appSend(message.getTitle(), message.getContent(), jgAlia, message.getId().toString(), StringUtils.isBlank(message.getLink())?"0":"1", message.getLink());
}
}
}
/**
* APP定时推送
* @param smsDataMap
*/
private void sendDelay(Map<String,Object> smsDataMap) {
//0为全部发送
if("0".equals(message.getReceiverGroupType())){
JPushScheduleClient.createSingleSchedule(
DateUtil.formatDateToStr("yyyy-MM-dd HH:mm:ss", message.getExpectTime()),
message.getTitle(),
message.getContent(),
message.getId().toString(),
StringUtils.isBlank(message.getLink())?"0":"1",
message.getLink());
}else{
String[] jgAlias = smsDataMap.get("jgAlias").toString().split(",");
JPushScheduleClient.createSingleSchedule(
Arrays.asList(jgAlias),
DateUtil.formatDateToStr("yyyy-MM-dd HH:mm:ss", message.getExpectTime()),
message.getTitle(),
message.getContent(),
message.getId().toString(),
StringUtils.isBlank(message.getLink())?"0":"1",
message.getLink());
}
}
/**
* 批量发送消息
* @param smsDataList
* @param message
*/
private void sendBatch(String smsDataListStr,Message message){
try {
//批量发送方法使用异步发送
if(!message.getContent().contains("退订回T")){
message.setContent(message.getContent()+"退订回T");
}
SmsUtils.batchExecuteTask(smsDataListStr, message.getContent());
//短信测试方法
//SmsUtils.batchExecuteTask(smsDataListStr, message.getContent(),true);
} catch (Exception e) {
e.printStackTrace();
logger.error("批量发送消息异常=>{}{}",smsDataListStr,e);
}
}
}
1 /**
2 * 批量发送消息
3 * @param smsDataList
4 * @param message
5 */
6 private void sendBatch(String smsDataListStr,Message message){
7 try {
8 //批量发送方法使用异步发送
9 if(!message.getContent().contains("退订回T")){
10 message.setContent(message.getContent()+"退订回T");
11 }
12 SmsUtils.batchExecuteTask(smsDataListStr, message.getContent());
13 //短信测试方法
14 //SmsUtils.batchExecuteTask(smsDataListStr, message.getContent(),true);
15 } catch (Exception e) {
16 e.printStackTrace();
17 logger.error("批量发送消息异常=>{}{}",smsDataListStr,e);
18 }
19 }
1 public static String sendSmsCL(String mobile, String content,String urlStr,String un, String pw, String rd) {
2 // 创建StringBuffer对象用来操作字符串
3 StringBuffer sb = new StringBuffer(urlStr+"?");
4 // 用户账号
5 sb.append("un="+un);
6
7 //用户密码
8 sb.append("&pw="+pw);
9
10 // 是否需要状态报告,0表示不需要,1表示需要
11 sb.append("&rd="+rd);
12
13 // 向StringBuffer追加手机号码
14 sb.append("&phone="+mobile);
15
16 // 返回发送结果
17 String inputline;
18 BufferedReader in = null;
19 InputStreamReader isr = null;
20 try {
21 // 向StringBuffer追加消息内容转URL标准码
22 sb.append("&msg="+URLEncoder.encode(content,"UTF8"));
23 // 创建url对象
24 URL url = new URL(sb.toString());
25
26 // 打开url连接
27 HttpURLConnection connection = (HttpURLConnection) url.openConnection();
28
29 // 设置url请求方式 ‘get’ 或者 ‘post’
30 connection.setRequestMethod("POST");
31 isr = new InputStreamReader(url.openStream());
32 // 发送
33 in = new BufferedReader(isr);
34 inputline = in.readLine();
35 if(inputline.contains(",0")){
36 logger.info("手机号:【{}】发送短信成功", mobile);
37 }else{
38 logger.info("手机号:【{}】发送短信失败,errorMsg is:{}", mobile,inputline);
39 }
40 // 输出结果
41 return inputline;
42 } catch (Exception e) {
43 logger.error("发送短信请求异常:{}", e.getMessage());
44 return e.getMessage();
45 } finally{
46 if(null != isr){
47 try {
48 isr.close();
49 } catch (IOException e) {
50 logger.error("关闭流异常:{}", e.getMessage());
51 }
52 }
53 if(null != in){
54 try {
55 in.close();
56 } catch (IOException e) {
57 logger.error("关闭流异常:{}", e.getMessage());
58 }
59 }
60 }
61
62 }
package com.bankhui.center.jpush;
import java.util.HashMap;
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* The entrance of JPush API library.
*
*/
public class JPushClient extends BaseClient {
private static Logger logger = LoggerFactory.getLogger(JPushClient.class);
//在极光注册上传应用的 appKey 和 masterSecret
private static final String appKeyStr ="******************";////必填,
private static final String masterSecretStr = "******************";//必填,每个应用都对应一个masterSecret
private static JPushClient jpush = null;
/*
* 保存离线的时长。秒为单位。最多支持10天(864000秒)。
* 0 表示该消息不保存离线。即:用户在线马上发出,当前不在线用户将不会收到此消息。
* 此参数不设置则表示默认,默认为保存1天的离线消息(86400秒
*/
private static long timeToLive = 60 * 60 * 24;
protected static HttpPostClient httpClient = new