极光推送REST API与Java后台对接

news2024/11/23 20:38:50

极光推送官网的web推送页面
在这里插入图片描述
因为是对接它的api,所以我参照这这个样式实现了一个,效果如下:

  • 定时任务推送界面,可定制。实现了推送一次和每日定时推送,如果再扩展的话有每周、每月的功能,只是没有这个业务需求。
    定时任务推送
  • 普通的单次消息推送
    单次消息推送

极光的官方文档地址:https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push
在这里插入图片描述

如果实在没看懂的话,也可以到官方的代码仓库把demo下下来看,有很多案例。地址:https://github.com/jpush/jpush-api-java-client.git。首先我们需要创建自己的应用程序,会给出appKeymasterSecret
在这里插入图片描述

下面贴一下我这边的关键代码,业务代码就省略了,具体可以根据自己的业务来实现

首先是引入jar包,由于我的是springcloud项目,所以其他的引用就省略了。
pom.xml

<dependency>
    <groupId>cn.jpush.api</groupId>
    <artifactId>jpush-client</artifactId>
    <version>3.6.6</version>
</dependency>

如果报错的话,可能还需要引入以下依赖

<dependency>
	<groupId>org.apache.httpcomponents</groupId>
	<artifactId>httpclient</artifactId>
	<version>4.5.3</version>
    <scope>compile</scope>
</dependency>
<dependency>
    <groupId>io.netty</groupId>
    <artifactId>netty-all</artifactId>
    <version>4.1.6.Final</version>
    <scope>compile</scope>
</dependency>
<dependency>
	<groupId>com.google.code.gson</groupId>
	<artifactId>gson</artifactId>
	<version>2.3</version>
</dependency>

通用的常量 Constants,用来判断是否设置为生产环境

/**
 * 生产环境标识
 */
public static final String PROD_ENV = "prod";

极光推送配置的读取,使用的是nacos作为配置中心,当然也可以写到本地
JPushConfig

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * 极光推送配置
 * @author: 
 * @date: 2023/1/4
 */
@Data
@Component
@ConfigurationProperties(prefix = "jpush.push")
public class JPushConfig {
    /**
     * AppKey
     */
    private String appKey;

    /**
     * 密钥
     */
    private String masterSecret;

    /**
     * 离线消息保留时长(秒)
     */
    private int liveTime;

    /**
     * 回调url
     */
    private String callback;
}

极光推送的常量
JPushConstants

package com.xx.config;

/**
 * JPush常量
 * @author: 
 * @date: 2023/1/4
 */
public class JPushConstants {
    /** 任务类型 */
    /** 普通类型 */
    public static final String TASK_TYPE_COMMON = "common";
    /** 定时任务 */
    public static final String TASK_TYPE_SCHEDULE = "schedule";

    /** 指定推送平台 */
    public static final String PLATFORM_ALL = "all";
    public static final String PLATFORM_ANDROID = "android";
    public static final String PLATFORM_IOS = "ios";
    public static final String PLATFORM_WINPHONE = "winphone";
    public static final String PLATFORM_ANDROID_IOS = "android_ios";
    public static final String PLATFORM_ANDROID_WINPHONE = "android_winphone";
    public static final String PLATFORM_IOS_WINPHONE = "ios_winphone";

    /** 指定推送目标 */
    /** 广播推送(全部设备) */
    public static final String AUDIENCE_ALL = "all";
    /** 标签推送,多个标签之间是 OR 的关系,即取并集。一次推送最多 20 个。 */
    public static final String AUDIENCE_TAG_AND = "tag_and";
    /** 标签推送,多个标签之间是 AND 关系,即取交集。一次推送最多 20 个。 */
    public static final String AUDIENCE_TAG_NOT = "tag_not";
    /** 标签推送,多个标签之间,先取多标签的并集,再对该结果取补集。一次推送最多 20 个。 */
    public static final String AUDIENCE_TAG = "tag";
    /** 别名推送,多个别名之间是 OR 关系,即取并集。一次推送最多 1000 个。 */
    public static final String AUDIENCE_ALIAS = "alias";
    /** 注册ID推送,多个注册ID之间是 OR 关系,即取并集。一次推送最多 1000 个。 */
    public static final String AUDIENCE_REGISTRATION_ID = "registration_id";
    /** 用户分群ID推送,定义为数组,但目前限制一次只能推送一个。 */
    public static final String AUDIENCE_SEGMENT = "segment";
    /** A/B Test ID推送,定义为数组,但目前限制是一次只能推送一个。 */
    public static final String AUDIENCE_ABTEST = "abtest";

    /** 指定通知对象 */
    public static final String NOTIFICATION_ANDROID = "android";
    public static final String NOTIFICATION_IOS = "ios";
    public static final String NOTIFICATION_ANDROID_IOS = "android_ios";
    public static final String NOTIFICATION_WINPHONE = "winphone";
}

从前端传入的附加字段Bean
Extra

@Data
public class Extra {
    String label;
    String value;
}

从前端传入的推送消息Bean,下面出现的SysMessage结构与其类似,故省略。
PushBean

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;

import javax.validation.constraints.NotBlank;
import java.util.List;
import java.util.Map;

/**
 * @author: 
 * @date: 2023/1/4
 */
@Data
public class PushBean {
    /**
     * 主键
     */
    private Long id;
    /**
     * 必填, 通知内容, 内容可以为空字符串,则表示不展示到通知栏
     */
    @NotBlank
    private String content;
    /**
     * 可选, 附加信息, 供业务使用
     */
    private List<Extra> extras;
    /**
     * android专用 可选, 通知标题,如果指定了,则通知里原来展示 App名称的地方,将展示成这个字段
     */
    private String title;
    /**
     * 指定推送平台
     */
    private String platform;
    /**
     * 指定推送范围
     */
    private String audience;
    /**
     * 指定推送目标
     */
    private List<String> audienceValues;
    /**
     * 任务类型: common(普通类型)、schedule(定时任务)
     */
    private String taskType;
    /**
     * 定时推送
     */
    private String time;
    /**
     * 请求参数
     */
    @JsonInclude(JsonInclude.Include.NON_EMPTY)
    private Map<String, String> params;
}

极光推送的关键代码,这里包含了推送业务和数据库的存储、读取(代码省略)。
JPushService

import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.ServiceHelper;
import cn.jiguang.common.connection.NativeHttpClient;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jiguang.common.resp.DefaultResult;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.*;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import cn.jpush.api.report.MessagesResult;
import cn.jpush.api.report.ReceivedsResult;
import cn.jpush.api.schedule.ScheduleMsgIdsResult;
import cn.jpush.api.schedule.ScheduleResult;
import com.alibaba.fastjson.JSONObject;
import com.google.common.collect.Lists;
import com.google.gson.JsonObject;
import com.xx.common.Constants;
import com.xx.exception.ServiceException;
import com.xx.utils.id.UUID;
import com.xx.utils.SecurityUtils;
import com.xx.config.JPushConfig;
import com.xx.config.JPushConstants;
import com.xx.domain.Extra;
import com.xx.domain.PushBean;
import com.xx.domain.SysMessage;
import com.xx.domain.SysMessageTarget;
import com.xx.mapper.SysMessageMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 极光推送
 * 封装第三方API
 *
 * @author: 
 * @date: 2023/1/4
 */
@Service
@Slf4j
public class JPushService {
    @Value("${spring.profiles.active}")
    private String profile;

    /**
     * 一次推送最大数量 (极光限制1000)
     */
    private static final int MAX_SIZE = 1000;

    @Autowired
    private JPushConfig config;
    @Autowired
    private SysMessageMapper messageMapper;


    /**
     * 向所有用户推送push消息
     *
     * @param pushBean
     * @return boolean
     */
    public boolean sendPush(PushBean pushBean) {
        SysMessage message = genSysMessage(pushBean);
        // 默认全部用户
        pushBean.setAudience(JPushConstants.AUDIENCE_ALL);
        PushPayload payload = buildPushPayload(pushBean, null, message.getCode());
        message.setSendNo(payload.getSendno());
        message.setPayload(payload.toString());
        boolean result;
        if (JPushConstants.TASK_TYPE_COMMON.equals(pushBean.getTaskType())) {
            result = sendPush(payload, message);
        } else {
            //定时推送
            String time = pushBean.getTime();
            Map<String, String> params = pushBean.getParams();
            result = createSchedule(params, time, payload, message);
        }
        if (pushBean.getId() != null) {
            messageMapper.updateMessage(message);
        } else {
            messageMapper.insertMessage(message);
        }
        return result;
    }

    /**
     * 分批推送push消息
     *
     * @param pushBean
     * @param audienceValues
     * @return boolean
     */
    public boolean sendPush(PushBean pushBean, List<String> audienceValues) {
        SysMessage message = genSysMessage(pushBean);
        boolean result = false;
        //由于jpush接口最大限制1000,需要分批推送
        List<List<String>> partition = Lists.partition(audienceValues, MAX_SIZE);
        // 推送push消息
        for (List<String> values : partition) {
            // 构建推送对象
            PushPayload payload = buildPushPayload(pushBean, values, message.getCode());
            message.setPayload(payload.toString());
            if (StringUtils.isBlank(message.getSendNo())) {
                message.setSendNo(payload.getSendno());
            }

            if (JPushConstants.TASK_TYPE_COMMON.equals(pushBean.getTaskType())) {
                result = sendPush(payload, message);
            } else {
                //定时推送
                String time = pushBean.getTime();
                Map<String, String> params = pushBean.getParams();
                result = createSchedule(params, time, payload, message);
            }

            if (result) {
                if (pushBean.getId() != null) {
                    //如果是修改,则把历史数据全部删除,然后再重新插入
                    SysMessage sysMessage = messageMapper.getMessageById(pushBean.getId());
                    messageMapper.deleteMessageTargetByCode(sysMessage.getCode());
                }
                // 批量保存指定用户的ID
                List<SysMessageTarget> list = new ArrayList<>(MAX_SIZE);
                values.forEach(item -> {
                    SysMessageTarget target = new SysMessageTarget();
                    target.setCode(message.getCode());
                    //未读状态
                    target.setStatus(0);
                    target.setTarget(item);
                    list.add(target);
                });
                messageMapper.batchAddMessageTarget(list);
            }
        }
        if (pushBean.getId() != null) {
            messageMapper.updateMessage(message);
        } else {
            messageMapper.insertMessage(message);
        }

        return result;
    }

    /**
     * 定时推送push消息
     *
     * @param time    定时
     * @param payload 推送对象
     * @return int
     */
    public boolean createSchedule(Map<String, String> params, String time, PushPayload payload, SysMessage message) {
        log.info("开始定时推送push消息:{}", payload);
        JPushClient jpushClient = buildJPushClient();
        try {
            ScheduleResult result;
            if (params == null || params.isEmpty()) {
                // 定时推送
                String name = "schedule_push_task";
                result = jpushClient.createSingleSchedule(name, time, payload, config.getMasterSecret(), config.getAppKey());
            } else {
                // 每日定时推送
                String name = "daily_schedule_push_task";
                // 开始日期
                String start = params.get("start");
                // 结束日期
                String end = params.get("end");
                message.setStart(start);
                message.setEnd(end);
                result = jpushClient.createDailySchedule(name, start, end, time, payload, config.getMasterSecret(), config.getAppKey());
            }
            log.info("定时推送请求完成: {}", result);
            message.setTime(time);
            message.setScheduleId(result.getSchedule_id());
            message.setEnabled(result.isResultOK());
            message.setStatus(result.isResultOK() ? 0 : 1);
            return result.isResultOK();
        } catch (APIConnectionException e) {
            log.error("Connection error. Should retry later. ", e);
            throw new ServiceException(e.getMessage());
        } catch (APIRequestException e) {
            log.error("Error response from JPush server. Should review and fix it. ", e);
            log.info("Error Code: " + e.getErrorCode());
            throw new ServiceException(e.getErrorMessage());
        }
    }

    /**
     * 推送push消息
     *
     * @param payload 推送对象
     * @return int
     */
    public boolean sendPush(PushPayload payload, SysMessage message) {
        log.info("开始推送push消息:{}", payload);
        JPushClient jpushClient = buildJPushClient();
        try {
            PushResult result = jpushClient.sendPush(payload);
            log.info("推送请求完成: {}", result);
            message.setMsgId(result.msg_id + "");
            message.setStatus(result.isResultOK() ? 0 : 1);
            return result.isResultOK();
        } catch (APIConnectionException e) {
            log.error("Connection error. Should retry later. ", e);
            throw new ServiceException(e.getMessage());
        } catch (APIRequestException e) {
            log.error("Error response from JPush server. Should review and fix it. {}", e.getErrorMessage());
            log.info("Error Code: " + e.getStatus());
            throw new ServiceException(e.getErrorMessage());
        }
    }

    /**
     * 生成JpushClient
     *
     * @return
     */
    private JPushClient buildJPushClient() {
        ClientConfig clientConfig = ClientConfig.getInstance();
        // ClientConfig.getInstance().setPushHostName("https://api.jpush.cn/v3/push");
        // ClientConfig.getInstance().setPushHostName("https://bjapi.push.jiguang.cn");
        clientConfig.setMaxRetryTimes(5);
        // 10 seconds
        clientConfig.setConnectionTimeout(10 * 1000);
        // JPush server supports SSLv3, TLSv1, TLSv1.1, TLSv1.2
        clientConfig.setSSLVersion("TLSv1.2");

        String authCode = ServiceHelper.getBasicAuthorization(config.getAppKey(), config.getMasterSecret());

        NativeHttpClient httpClient = new NativeHttpClient(authCode, null, clientConfig);

        JPushClient jpushClient = new JPushClient(config.getMasterSecret(), config.getAppKey(), null, clientConfig);
        jpushClient.getPushClient().setHttpClient(httpClient);
        return jpushClient;
    }

    /**
     * 构建推送对象
     *
     * @param pushBean 参数
     * @return PushPayload
     */
    private PushPayload buildPushPayload(PushBean pushBean, List<String> audienceValues, String code) {
        List<Extra> extrasArr = pushBean.getExtras();
        Map<String, String> extras = CollectionUtils.isEmpty(extrasArr) ? null : extrasArr.stream().collect(Collectors.toMap(Extra::getLabel, Extra::getValue));

        return PushPayload.newBuilder()
                // Platform指定推送平台
                .setPlatform(buildPlatform(pushBean.getPlatform()))
                // Audience指定推送目标
                .setAudience(buildAudience(pushBean.getAudience(), audienceValues))
                // Notification推送通知内容体
                .setNotification(buildNotification(pushBean, extras))
                // 构建回调信息
                .addCustom("callback", buildCallback(config.getCallback(), code))
                // Message推送通知内容体
                .setMessage(buildMessage(pushBean.getContent(), extras))
                // 应用内提醒,当用户前台运行 APP 时,会通过应用内消息的方式展示通知栏消息内容
                .setInappMessage(InappMessage.newBuilder().setInappMessage(true).build())
                // Options推送参数,设置离线消息保留时长
                .setOptions(Options.newBuilder()
                        //推送当前用户不在线时,为该用户保留多长时间的离线消息,以便其上线时再次推送。默认 86400 (1 天)
                        .setTimeToLive(config.getLiveTime())
                        //该字段仅对 iOS 的 Notification 有效,  true:表示推送生产环境。false:表示推送开发环境, 默认
                        .setApnsProduction(Constants.PROD_ENV.equals(profile))
                        //API 调用标识
                        //.setSendno()
                        .build())
                .build();
    }


    /**
     * 构建通知内容体
     *
     * @param pushBean 通知
     * @param extras   扩展字段
     * @return Notification
     */
    private Notification buildNotification(PushBean pushBean, Map<String, String> extras) {
        Notification.Builder notification = Notification.newBuilder()
                // alert通知,推送到Platform指定的多个平台
                .setAlert(pushBean.getContent())
                // 构建Android平台上的通知结构
                .addPlatformNotification(androidNotificationBuilder(pushBean, extras))
                // 构建iOS平台上的通知结构
                .addPlatformNotification(iosNotificationBuilder(pushBean, extras));
        return notification.build();
    }

    /**
     * 构建通知内容体
     *
     * @param message 通知内容
     * @param extras  扩展字段
     * @return Notification
     */
    private Message buildMessage(String message, Map<String, String> extras) {
        if (extras == null || extras.isEmpty()) {
            return Message.newBuilder().setMsgContent(message).build();
        }
        return Message.newBuilder().setMsgContent(message).addExtras(extras).build();
    }

    /**
     * 处理附加信息
     *
     * @param extras
     * @return
     */
    private IosNotification iosNotificationBuilder(PushBean pushBean, Map<String, String> extras) {
        if (extras == null || extras.isEmpty()) {
            return IosNotification.newBuilder()
                    .setAlert(pushBean.getContent())
                    .incrBadge(1)
                    .build();
        }
        return IosNotification.newBuilder()
                .setAlert(pushBean.getContent())
                //通知扩展,说明是支持 iOS 10 的 UNNotificationServiceExtension
                //.setMutableContent(true)
                .incrBadge(1)
                // 这个 key(my-attachment)值,需要与客户端的值对应,客户端工程拿到 key 值对应的 url 图标加载出来
                // .addExtra("my-attachment","https://raw.githubusercontent.com/Tikon/imgRepo/master/ic_launcher.png")
                .addExtras(extras)
                .build();
    }

    /**
     * 处理附加信息
     *
     * @param extras
     * @return
     */
    private AndroidNotification androidNotificationBuilder(PushBean pushBean, Map<String, String> extras) {
        String title = pushBean.getTitle();
        String msg = pushBean.getContent();
        //文本条目通知栏样式
        JsonObject inbox = new JsonObject();
        inbox.addProperty("key", "value");
        //跳转路径,应用首页
        JsonObject intent = new JsonObject();
        intent.addProperty("url", "intent:#Intent;action=android.intent.action.MAIN;end");
        if (extras == null || extras.isEmpty()) {
            return AndroidNotification.newBuilder()
                    //通知内容
                    .setAlert(msg)
                    //通知提醒方式, 可选范围为 -1~7 ,默认-1, 即0111二进制,左数第二位代表 light,第三位代表 vibrate,第四位代表 sound。 0:不生效,1:生效
                    .setAlertType(-1)
                    //通知标题
                    .setTitle(title)
                    //通知栏展示优先级,默认为 0,范围为 -2~2
                    .setPriority(0)
                    //通知栏样式类型,默认为 0, 1-bigText; 2-Inbox; 3-bigPicture
                    //.setStyle(3)
                    //大文本通知栏样式,style=1时生效
                    //.setBigText(msg)
                    //文本条目通知栏样式,style=2时生效,json 的每个 key 对应的 value 会被当作文本条目逐条展示
                    //.setInbox(inbox)
                    //大图片通知栏样式,style=3时生效
                    //.setBigPicPath("")
                    //通知栏大图标
                    //.setLargeIcon("")
                    //通知栏小图标
                    //.setSmallIconUri("")
                    //指定跳转页面,三种类型:
                    // 1. 跳转到目标页: intent:#Intent;action=action 路径;component= 包名 /Activity 全名;end      (OPPO 和 FCM 通道必须传 "action 路径", 其他厂商必须传 "Activity 全名", 否则将出现对应厂商无法跳转问题)
                    // 2. 跳转到deeplink地址: scheme://test?key1=val1&key2=val2
                    // 3. 应用首页: intent:#Intent;action=android.intent.action.MAIN;end  (固定为此地址)
                    //.setIntent(intent)
                    //通知栏样式 ID
                    .setBuilderId(2)
                    //定时展示开始时间(yyyy-MM-dd HH:mm:ss),默认立即展示
                    //.setShowBeginTime("")
                    .build();
        }
        return AndroidNotification.newBuilder()
                //通知内容
                .setAlert(msg)
                //通知提醒方式, 可选范围为 -1~7 ,默认-1, 即0111二进制,左数第二位代表 light,第三位代表 vibrate,第四位代表 sound。 0:不生效,1:生效
                .setAlertType(-1)
                //通知标题
                .setTitle(title)
                //通知栏展示优先级,默认为 0,范围为 -2~2
                .setPriority(0)
                //通知栏样式类型,默认为 0, 1-bigText; 2-Inbox; 3-bigPicture
                //.setStyle(3)
                //大文本通知栏样式,style=1时生效
                //.setBigText(msg)
                //文本条目通知栏样式,style=2时生效,json 的每个 key 对应的 value 会被当作文本条目逐条展示
                //.setInbox(inbox)
                //大图片通知栏样式,style=3时生效
                //.setBigPicPath("https://lmg.jj20.com/up/allimg/1114/040221103339/210402103339-10-1200.jpg")
                //通知栏大图标
                //.setLargeIcon("")
                //通知栏小图标
                //.setSmallIconUri("")
                //指定跳转页面,三种类型:
                // 1. 跳转到目标页: intent:#Intent;action=action 路径;component= 包名 /Activity 全名;end      (OPPO 和 FCM 通道必须传 "action 路径", 其他厂商必须传 "Activity 全名", 否则将出现对应厂商无法跳转问题)
                // 2. 跳转到deeplink地址: scheme://test?key1=val1&key2=val2
                // 3. 应用首页: intent:#Intent;action=android.intent.action.MAIN;end  (固定为此地址)
                //.setIntent(intent)
                //通知栏样式 ID
                .setBuilderId(2)
                //定时展示开始时间(yyyy-MM-dd HH:mm:ss),默认立即展示
                //.setShowBeginTime("")
                //扩展字段
                .addExtras(extras)
                .build();
    }


    /**
     * 构建推送平台
     *
     * @param platform 指定推送平台
     * @return Platform
     */
    private Platform buildPlatform(String platform) {
        switch (platform) {
            case JPushConstants.PLATFORM_ANDROID:
                return Platform.android();
            case JPushConstants.PLATFORM_IOS:
                return Platform.ios();
            case JPushConstants.PLATFORM_WINPHONE:
                return Platform.winphone();
            case JPushConstants.PLATFORM_ANDROID_IOS:
                return Platform.android_ios();
            case JPushConstants.PLATFORM_ANDROID_WINPHONE:
                return Platform.android_winphone();
            case JPushConstants.PLATFORM_IOS_WINPHONE:
                return Platform.ios_winphone();
            default:
                return Platform.all();
        }
    }

    /**
     * 构建推送目标
     *
     * @param audience       指定推送范围
     * @param audienceValues 指定推送目标
     * @return Audience
     */
    private Audience buildAudience(String audience, List<String> audienceValues) {
        switch (audience) {
            case JPushConstants.AUDIENCE_TAG:
                return Audience.tag(audienceValues);
            case JPushConstants.AUDIENCE_TAG_AND:
                return Audience.tag_and(audienceValues);
            case JPushConstants.AUDIENCE_TAG_NOT:
                return Audience.tag_not(audienceValues);
            case JPushConstants.AUDIENCE_ALIAS:
                return Audience.alias(audienceValues);
            case JPushConstants.AUDIENCE_REGISTRATION_ID:
                return Audience.registrationId(audienceValues);
            case JPushConstants.AUDIENCE_SEGMENT:
                return Audience.segment(audienceValues);
            case JPushConstants.AUDIENCE_ABTEST:
                return Audience.abTest(audienceValues);
            default:
                return Audience.all();
        }
    }

    /**
     * 构建回调信息
     *
     * @return
     */
    private JsonObject buildCallback(String url, String code) {
        JsonObject callback = new JsonObject();
        //回调url
        callback.addProperty("url", url);
        JsonObject params = new JsonObject();
        //唯一标识
        params.addProperty("code", code);
        callback.add("params", params);
        // 可选,1: 送达回执, 2: 点击回执, 3: 送达和点击回执, 8: 推送成功回执, 9: 成功和送达回执, 10: 成功和点击回执, 11: 成功和送达以及点击回执
        callback.addProperty("type", 3);
        return callback;
    }

    /**
     * 装配SysMessage
     *
     * @param pushBean 前端传的参数
     * @return SysMessage
     */
    private SysMessage genSysMessage(PushBean pushBean) {
        SysMessage message = new SysMessage();
        if (pushBean.getId() != null) {
            message = messageMapper.getMessageById(pushBean.getId());
        } else {
            message.setCode(UUID.fastUUID().toString(true));
        }

        message.setAudience(pushBean.getAudience());
        message.setContent(pushBean.getContent());
        message.setTitle(pushBean.getTitle());
        message.setPlatform(pushBean.getPlatform());
        message.setType("notification");
        message.setTaskType(pushBean.getTaskType());
        if (!CollectionUtils.isEmpty(pushBean.getExtras())) {
            message.setExtras(JSONObject.toJSONString(pushBean.getExtras()));
        }
        message.setCreateBy(SecurityUtils.getUsername());
        return message;
    }

    /**
     * 撤回推送消息
     *
     * @param msgId
     * @return
     * @throws APIConnectionException
     * @throws APIRequestException
     */
    public boolean delMessage(String msgId) {
        try {
            JPushClient jpushClient = buildJPushClient();
            DefaultResult result = jpushClient.deletePush(msgId);
            log.info("撤回推送消息请求完成: {}", result);
            return result.isResultOK();
        } catch (APIConnectionException e) {
            log.error("Connection error. Should retry later. ", e);
            throw new ServiceException(e.getMessage());
        } catch (APIRequestException e) {
            log.error("Error response from JPush server. Should review and fix it. {}", e.getErrorMessage());
            log.info("Error Code: " + e.getStatus());
            throw new ServiceException(e.getErrorMessage());
        }
    }

    /**
     * 删除定时任务
     *
     * @param scheduleId
     * @return
     * @throws APIConnectionException
     * @throws APIRequestException
     */
    public boolean delSchedule(String scheduleId) {
        try {
            JPushClient jpushClient = buildJPushClient();
            jpushClient.deleteSchedule(scheduleId);
            return Boolean.TRUE;
        } catch (APIConnectionException e) {
            log.error("Connection error. Should retry later. ", e);
            throw new ServiceException(e.getMessage());
        } catch (APIRequestException e) {
            log.error("Error response from JPush server. Should review and fix it. {}", e.getErrorMessage());
            log.info("Error Code: " + e.getStatus());
            throw new ServiceException(e.getErrorMessage());
        }
    }

    /**
     * 禁用定时任务
     *
     * @param scheduleId
     * @return
     * @throws APIConnectionException
     * @throws APIRequestException
     */
    public boolean disableSchedule(String scheduleId) {
        try {
            JPushClient jpushClient = buildJPushClient();
            ScheduleResult result = jpushClient.disableSchedule(scheduleId);
            log.info("禁用定时任务请求完成: {}", result);
            boolean ok = result.isResultOK();
            return ok;
        } catch (APIConnectionException e) {
            log.error("Connection error. Should retry later. ", e);
            throw new ServiceException(e.getMessage());
        } catch (APIRequestException e) {
            log.error("Error response from JPush server. Should review and fix it. {}", e.getErrorMessage());
            log.info("Error Code: " + e.getStatus());
            throw new ServiceException(e.getErrorMessage());
        }
    }

    /**
     * 启用定时任务
     *
     * @param scheduleId
     * @return
     * @throws APIConnectionException
     * @throws APIRequestException
     */
    public boolean enableSchedule(String scheduleId) {
        try {
            JPushClient jpushClient = buildJPushClient();
            ScheduleResult result = jpushClient.enableSchedule(scheduleId);
            log.info("启用定时任务请求完成: {}", result);
            boolean ok = result.isResultOK();
            return ok;
        } catch (APIConnectionException e) {
            log.error("Connection error. Should retry later. ", e);
            throw new ServiceException(e.getMessage());
        } catch (APIRequestException e) {
            log.error("Error response from JPush server. Should review and fix it. {}", e.getErrorMessage());
            log.info("Error Code: " + e.getStatus());
            throw new ServiceException(e.getErrorMessage());
        }
    }

    /**
     * 获取定时任务的的msgIds
     *
     * @param scheduleId
     * @return
     * @throws APIConnectionException
     * @throws APIRequestException
     */
    public ScheduleMsgIdsResult getScheduleMsgIds(String scheduleId) {
        try {
            JPushClient jpushClient = buildJPushClient();
            ScheduleMsgIdsResult result = jpushClient.getScheduleMsgIds(scheduleId);
            log.info("获取定时任务的的msgIds请求完成: {}", result);
            return result;
        } catch (APIConnectionException e) {
            log.error("Connection error. Should retry later. ", e);
            throw new ServiceException(e.getMessage());
        } catch (APIRequestException e) {
            log.error("Error response from JPush server. Should review and fix it. {}", e.getErrorMessage());
            log.info("Error Code: " + e.getStatus());
            throw new ServiceException(e.getErrorMessage());
        }
    }

    /**
     * 根据msgId获取推送统计
     *
     * @param msgId
     * @return
     * @throws APIConnectionException
     * @throws APIRequestException
     */
    public ReceivedsResult getReport(String msgId) {
        try {
            JPushClient jpushClient = buildJPushClient();
            ReceivedsResult result = jpushClient.getReportReceiveds(msgId);
            //测试账号没有下面这个api的权限,会报错
            MessagesResult messages = jpushClient.getReportMessages(msgId);
            return result;
        } catch (APIConnectionException e) {
            log.error("Connection error. Should retry later. ", e);
            throw new ServiceException(e.getMessage());
        } catch (APIRequestException e) {
            log.error("Error response from JPush server. Should review and fix it. {}", e.getErrorMessage());
            log.info("Error Code: " + e.getStatus());
            throw new ServiceException(e.getErrorMessage());
        }
    }

}

本篇就介绍到这里了。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/169858.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

银行数字化转型导师坚鹏:银行数字化转型的五大痛点

首先从汇丰银行业绩持续下滑谈起&#xff0c;汇丰银行作为一家国际知名的全球性银行&#xff0c;最近10年左右的时间里&#xff0c;营业收入持续下降&#xff0c;已经从2008年的1400多亿美元到2021年的804.29亿美元; 净利润徘徊不前,2021年比2020年下降29.2%&#xff0c;仅为52…

kafka心得记录

1.为何引入kafka? 削峰填谷,主要还是为了应对上游瞬时大流量的冲击&#xff0c;避免出现流量毛刺现象&#xff0c;保护下游应用和数据库不被大流量打垮。 2.kafka备份机制&#xff0c;主从机制&#xff0c;Leader-Follower&#xff1a; Kafka 定义了两类副本&#xff1a;领导…

C语言文件操作函数详解——将你的代码永久化 ( •̀ ω •́ )✧

&#x1f384;博客主页&#xff1a;&#x1f390;大明超听话 &#x1f38b;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;关注✍评论 &#x1f38d;系列专栏&#xff1a;&#x1f391;从零开始C语言 &#x1f38a;从0开始数据结构与算法详解 &#x1f386;计算机考研——…

JavaScript中的原型链

本文作者为奇舞团前端开发工程师概述JavaScript 是 Web 的编程语言&#xff0c;简单易学&#xff0c;功能强大&#xff0c;但由于过于灵活设计理念&#xff0c;导致初学者经常一脸懵&#xff0c;本文要谈的是JavaScript中难点之一原型链。原型链的前世JavaScript的诞生要理解Ja…

Nessus介绍与安装

Nessus介绍与安装 1.Nessus简介 Nessus号称是世界上最流行的漏洞扫描程序&#xff0c;全世界有超过75000个组织在使用它。该工具提供完整的电脑漏洞扫描服务&#xff0c;并随时更新其漏洞数据库。Nessus不同于传统的漏洞扫描软件&#xff0c;Nessus可同时在本机或远端上遥控&…

测试开发 | Dubbo 接口测试原理及多种方法实践总结

image1080478 86.9 KB 1、什么是 Dubbo&#xff1f; Dubbo 最开始是应用于淘宝网&#xff0c;由阿里巴巴开源的一款优秀的高性能服务框架&#xff0c;由 Java 开发&#xff0c;后来贡献给了 Apache 开源基金会组织。 下面以官网的一个说明来了解一下架构的演变过程&#xff0…

初学Java中的方法,看这篇就够了

本篇介绍了Java中方法的概念以及方法的使用(方法的定义和调用,实参和形参的关系).方法重载的介绍和使用,编译器如何实现方法重载- -方法签名,介绍和使用方法调用自身解决问题的技巧–递归 对比递归和循环的优缺点 掌握Java中的方法一.方法的概念及使用1.什么是方法2.方法的使用…

【C++】AVL树

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;AVL树&am…

【Linux】CentOS、CentOS Stream、RedHat 和Fedora 之间的关系

目录 简单说明 详细说明 红帽&#xff08;Red Hat&#xff09;系和德班&#xff08;Debian&#xff09;系 简单说明 在centos8之前&#xff1a; Fedora 》RedHat 》CentOS Fedora 是RedHat的“试验场”&#xff0c;很多新功能和特性先加入Fedora 稳定后再加入RedHat&…

YOLOv5 引入 最新 BiFusion Neck | 附详细结构图

YOLO 社区自前两次发布以来一直情绪高涨&#xff01;随着中国农历新年2023兔年的到来&#xff0c;美团对YOLOv6进行了许多新的网络架构和训练方案改进。此版本标识为 YOLOv6 v3.0。对于性能&#xff0c;YOLOv6-N在COCO数据集上的AP为37.5%&#xff0c;通过NVIDIA Tesla T4 GPU测…

99.恢复二叉搜索树

99.恢复二叉搜索树 1、题目描述 题目的额外要求是: 使用 O(n) 空间复杂度的解法很容易实现。你能想出一个只使用 O(1) 空间的解决方案吗&#xff1f; 2、解题思路 二叉搜索树中某两个节点被交换了数值&#xff0c;那么对中序序列的影响如下&#xff1a; 假设没有交换之前二叉…

活动星投票千人共读一本书网络评选微信的投票方式线上免费投票

“千人共读一本书”网络评选投票_视频投票评选_投票统计小程序_微信不记名投票用户在使用微信投票的时候&#xff0c;需要功能齐全&#xff0c;又快捷方便的投票小程序。而“活动星投票”这款软件使用非常的方便&#xff0c;用户可以随时使用手机微信小程序获得线上投票服务&am…

正则表达式和re模块

目录 一.基础匹配 1.什么是正则表达式 re模块三个基础方法 re.match(匹配规则&#xff0c;被匹配字符串) search(匹配规则&#xff0c;被匹配字符串) findall(匹配规则&#xff0c;被匹配字符串) 小结 二.元字符匹配 单字符匹配: 示例: 数量匹配 边界匹配 分组匹配…

【Java】【系列篇】【Spring源码解析】【三】【体系】【BeanFactory体系】

BeanFactory体系BeanFactory整体结构体系图顶层接口-BeanFactory1.1、描述1.2、方法解析&#xff08;15个&#xff09;1.2.1、属性1.2.2、获取bean实例1.2.3、获取bean的提供者&#xff08;对象工厂&#xff09;1.2.4、判断是否包含bean1.2.5、单例,原型,bean类型的判断1.2.6、…

SAP ABAP——SAP包(二)【CTS | 传输请求】

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计专业大二本科在读&#xff0c;阿里云社区专家博主&#xff0c;华为云社区云享专家&#xff0c;CSDN SAP应用技术领域新兴创作者。   在学习工…

CentOS7.9配置Nginx反向代理+NodeJS部署上线

Nginx配置 Nginx是一个高性能的HTTP和反向代理服务&#xff0c;许多的大型网站都会采用Nginx来进行HTTP服务器托管 安装编译环境gcc g 进入到root目录&#xff1a; yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel 安装PCRE PCRE功能时让Ngi…

ue4c++日记3(碰撞报告碰撞位置|力和扭矩)

目录 代码速查 根据世界方向/局部方向移动 根据世界方向/局部方向旋转 加力加扭矩 1碰撞并报告碰撞位置 两个设为阻挡才会阻挡&#xff0c;其中一个是重叠就会重叠 2例子&#xff1a;旋转前进&#xff01;/原地踏步&#xff1f; 3增加力和扭矩 1.头文件 2.cpp文件 …

(14)go-micro微服务服务层Handle开发

文章目录一 Handle层开发功能说明需要完成的服务开发功能&#xff1a;从哪找需要开发的功能二 代码编写三 最后一 Handle层开发功能说明 需要完成的服务开发功能&#xff1a; 登录注册查询用户信息修改信息发送注册邮件发送重置密码邮件重置密码获取权限修改权限退出账号删除…

【计算机视觉】梯度消失和爆炸以及解决方法

问题 梯度消失无论是笔试还是面试都是常客了,其实对应于梯度消失,还有一个梯度爆炸的概念,这又是什么导致的呢?下面我们将根据公式推导来解释何为梯度消失与梯度爆炸。 梯度消失和梯度爆炸的表现 网络层数越多,模型训练的时候便越容易出现 梯度消失(gradient vanish) 和…

史上最全| 14种自动化分拣系统合集

导语大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;你的老朋友&#xff0c;老K。新书上市《智能物流系统构成与技术实践》2023年度-厂商宣传合作位--->点击详情本文为研习社原创&#xff0c;违规转载必究01移栽式02偏转轮式03扫臂式04滑靴式05侧向翻转06推…