之前一直没做过跟推送有关的东西,也没接触过实例,现在逮着机会遇到了一个实例,准备mark起来。
这个功能大致是这样的:一个后台管理系统进行消息推送的管理,设置时间和推送的内容,还有推送的类型进行保存,不管是极光推送还是短信推送还是指定用户的推送,定时任务每隔一段时间扫到了这个任务,当数据库有消息没有被推送出去的时候,按照存储的推送类型进行判断然后推送。后台配置系统大概是这个样子的。
它这个也不知道哪个二货写的代码,乱七八糟的,我就捡主要的举个栗子吧。
1.上面已经说了它这个是拿spring-quartz定时任务扫的,具体怎么实现的我有博客可以看看。触发定时方法,首先去库里面扫有没有定时任务没有执行的,如果有没执行的则将其执行,并从库中取出来参数拼接进行消息推送。
public void work() {
LOGGER.info("开始检索是否有需要发送的信息");
Map<String,Object> map=new HashMap<>();
//5分钟后待发送
map.put("status", 1);
map.put("carryOn", "carryOn");
List<MessageManage> msgs=MessageManageDao.selectObjectList(map);
if(msgs!=null && msgs.size()>0){
LOGGER.info("检索到需要发送的消息",msgs);
SendMsgThread sendThread=new SendMsgThread(tSeUnagentService,MessageManageDao,msgs,AppChannelService);
sendThread.start();
}
LOGGER.info("结束信息检索");
}
大概就是这个意思,MessageManageDao的方法就是扫描库里面是否有没推送的消息,如果有则执行SendMsgThread方法进行消息推送。它这个开了多线程进行推送的,但是性能怎样我没有进行测试过,不知道会不会耗太多资源。目前为百万级别的用户量,暂时还没出现过问题。
2.SendMsgThread方法继承了Thread类,我先贴出来代码。
public class SendMsgThread extends Thread {
private static final Logger LOGGER = LoggerFactory.getLogger(SendMsgThread.class);
private TSeUnagentService tSeUnagentService;
private MessageManageDao MessageManageDao;
private AppChannelService AppChannelService;
List<MessageManage> msgs;
public SendMsgThread(
TSeUnagentService tSeUnagentService,
MessageManageDao messageManageDao,
List<MessageManage> msgs,
AppChannelService AppChannelService
) {
super();
this.tSeUnagentService = tSeUnagentService;
this.MessageManageDao = messageManageDao;
this.msgs = msgs;
this.AppChannelService=AppChannelService;
}
@Override
public void run() {
/*
* 消息类型 Msg:短信 stationMsg:站内消息 pushMsg:推送消息
*/
for (MessageManage mm : msgs) {
try {
switch (mm.getType()) {
//这些全部省略掉没用
case "pushMsg":
JPushData jPushData = new JPushData();
//推送标题名
jPushData.setTitle(mm.getTitle());
//推送内容
jPushData.setContent(mm.getContent());
Map<String,String> extras = new HashMap<String, String>();
/*接收方: 全部用户:all, 近3个月活跃用户:3monthActiveUser,
* 近6个月活跃用户:6monthActiveUser, 近9个月活跃用户:9monthActiveUser,
* 当年活跃用户:yearActiveUser*/
switch(mm.getReceiveUser()){
case "all":
PushManage.sendAllPush(jPushData.getContent());
break;
case "uf":
//略
break;
case "3monthActiveUser":
//略
break;
mm.setStatus("2");
} catch (NumberFormatException e) {
mm.setStatus("3");
LOGGER.info(e.getMessage());
}
MessageManageDao.update(mm);
}
}
}
发现有未推送的消息,也就是status值为1的消息就进行处理,然后取出type值,进行短信推送还是消息推送,短信的话不说了我有文,直接上消息推送吧。
JPushData就是组装数据的实体类,大概长这样的。
public class JPushData {
private String title; //推送标题
private String content; //推荐内容
private List<String> tags; //推送分类标签
private List<String> alias; //推送别名
}
把要推送的东西组装好以后,就调用PushManage中的sendAllPush进行全体消息推送了。
/**
*
* @comment: 极光推送管理
*/
public class PushManage {
protected static final Logger log = LoggerFactory.getLogger(PushManage.class);
private static JPushClient memberJpushClient = null; //推送客户端
static{
memberJpushClient = new JPushClient(JpushConfig.MASTER_SECRET, JpushConfig.APP_KEY, JpushConfig.MAX_RETRY_TIMES);
}
public static void sendAllPush(String msgContent) {
PushPayload payload = buildPushObject_all_all_alert(msgContent);
payload.resetOptionsApnsProduction(true);
PushResult result=null;
try {
result = memberJpushClient.sendPush(payload);
log.info("Got result - " + result);
} catch (APIConnectionException e) {
log.error("Connection error. Should retry later. ", e);
} catch (APIRequestException e) {
log.error("Error response from JPush server. Should review and fix it. ", e);
log.info("HTTP Status: " + e.getStatus());
log.info("Error Code: " + e.getErrorCode());
log.info("Error Message: " + e.getErrorMessage());
log.info("Msg ID: " + e.getMsgId());
}
System.out.println(result);
}
public static void sendMemberPush(List<TSeUnagent> uns,JPushData jPushData){
for (TSeUnagent tSeUnagent : uns) {
sendMemberPush(tSeUnagent.getUnid(),jPushData.getContent());
}
}
/**
*
* @comment: 所有平台,所有设备,内容为 ALERT 的通知。
*/
public static PushPayload buildPushObject_all_all_alert(String msgContent) {
PushPayload build = PushPayload.newBuilder()
.setPlatform(Platform.all())
.setAudience(Audience.all())
.setNotification(Notification.newBuilder()
.addPlatformNotification(AndroidNotification.newBuilder()
.setAlert(msgContent)
.build())
.addPlatformNotification(IosNotification.newBuilder()
.setAlert(msgContent)
.setSound("happy.caf")
.setBadge(0)
.build())
.build())
.build();
return build;
// return PushPayload.alertAll(msgContent);
}
/**
*
* @comment: 构建推送对象:所有平台,推送目标是别名为 "alias",通知内容为 ALERT
*/
public static PushPayload buildPushObject_all_alias_alert(String alias,String msgContent) {
return PushPayload.newBuilder()
.setPlatform(Platform.all())
.setAudience(Audience.alias(alias))
.setNotification(Notification.newBuilder().setAlert(msgContent)
.addPlatformNotification(AndroidNotification.newBuilder()
.build())
.addPlatformNotification(IosNotification.newBuilder()
.setSound("happy.caf")
.setBadge(0)
.build())
.build())
.build();
}
/**
*
* @comment: 平台是 Android,目标是 tag 为 "tag" 的设备,内容是 Android 通知 msgContent,并且标题为 TITLE。
*/
public static PushPayload buildPushObject_android_tag_alertWithTitle(List<String> tag,String msgTitle,String msgContent) {
return PushPayload.newBuilder()
.setPlatform(Platform.all())
.setAudience(Audience.tag(tag))
.setNotification(Notification.android(msgContent, msgTitle, null))
.build();
}
public static PushPayload buildPushObject_android_and_ios(String tag,String msgTitle,String msgContent) {
return PushPayload.newBuilder()
.setPlatform(Platform.android_ios())
.setAudience(Audience.tag(tag))
.setNotification(Notification.newBuilder().setAlert(msgContent)
.addPlatformNotification(AndroidNotification.newBuilder()
.setTitle(msgTitle)
.build())
.addPlatformNotification(IosNotification.newBuilder()
.incrBadge(1)
.setBadge(0)
.setSound("happy")
.build())
.build())
.build();
}
//平台是 iOS,推送目标是 "tag1", "tag2" 的交集,推送内容同时包括通知与消息 - 通知信息是 ALERT,角标数字为 5,
//通知声音为 "happy",并且附加字段 from = "JPush";消息内容是 MSG_CONTENT。通知是 APNs 推送通道的,
//消息是 JPush 应用内消息通道的。APNs 的推送环境是“生产”(如果不显式设置的话,Library 会默认指定为开发)
public static PushPayload buildPushObject_ios_tagAnd_alertWithExtrasAndMessage(String tag1,String tag2,String msgTitle,String msgContent) {
return PushPayload.newBuilder()
.setPlatform(Platform.ios())
.setAudience(Audience.tag_and(tag1,tag2))
.setNotification(Notification.newBuilder()
.addPlatformNotification(IosNotification.newBuilder()
.setAlert(msgTitle)
.setBadge(5)
.setSound("happy")
.addExtra("from", "JPush")
.build())
.build())
.setMessage(Message.content(msgContent))
.setOptions(Options.newBuilder()
.setApnsProduction(true)
.build())
.build();
}
//平台是 Andorid 与 iOS,推送目标是 ("tag1" 与 "tag2" 的并集)且("alias1" 与 "alias2" 的并集),
//推送内容是 - 内容为 MSG_CONTENT 的消息,并且附加字段 from = JPush
public static PushPayload buildPushObject_ios_audienceMore_messageWithExtras(String tag1,String tag2,String alias1,String alias2,String msgTitle,String msgContent) {
return PushPayload.newBuilder()
.setPlatform(Platform.android_ios())
.setAudience(Audience.newBuilder()
.addAudienceTarget(AudienceTarget.tag(tag1, tag2))
.addAudienceTarget(AudienceTarget.alias(alias1, alias2))
.build())
.setMessage(Message.newBuilder()
.setMsgContent(msgContent)
.addExtra("from", "JPush")
.build())
.build();
}
//调用推送方法测试
public static void main(String[] args) {
JPushData jPushData = new JPushData();
String content = "测试测试测试测试";
String title = "测试";
String id = "123";
//推送标题名
jPushData.setTitle(title);
//推送内容
jPushData.setContent(content);
//推送需要传递的数据json,无数据可以不传
Map<String,String> extras = new HashMap<String, String>();
extras.put("orgId", "1");//地址h5页面
//定义添加标签名字,极光服务器会根据注册时的接口关键此标签,
List<String> tagColl = new ArrayList<String>();
tagColl.add("buall");//组织机构ID 北京
tagColl.add("all");//组织机构ID 北京
tagColl.add("9999");//组织机构ID 北京
//推送所有
//sendAllPush(jPushData.getContent());//全部推送
//个推,按照unid 集合推送
sendMemberPush(unid,jPushData.getContent());
//按照标签推送
//sendAllTagPush(jPushData.getTags(),jPushData.getTitle(),jPushData.getContent());
}
我把所有能用到的东西都贴出来方便下次直接用,具体什么原理就不去抠了,因为基本上都是jpush的jar包中的东西。上面的MASTER_SECRET、APP_KEY以及MAX_RETRYTIMES分别为 密钥、应用的唯一标识以及最大重试次数。这样推送完毕之后将数据库的字段进行更新,一条配置好了的数据就推送成功了。