Bladeren bron

优化极光推送逻辑

woody 1 jaar geleden
bovenliggende
commit
ff82ec20a0

+ 9 - 0
framework-base/src/main/java/com/chelvc/framework/base/context/ApplicationContextHolder.java

@@ -83,6 +83,15 @@ public class ApplicationContextHolder implements ApplicationContextAware {
         APPLICATION_CONTEXT = applicationContext;
     }
 
+    /**
+     * 判断是否是生产环境
+     *
+     * @return true/false
+     */
+    public static boolean isProduction() {
+        return getSafeProperty("environment.production", boolean.class, false);
+    }
+
     /**
      * 获取应用上下文对象
      *

+ 15 - 131
framework-jpush/src/main/java/com/chelvc/framework/jpush/DefaultJPushHandler.java

@@ -1,26 +1,14 @@
 package com.chelvc.framework.jpush;
 
-import java.lang.reflect.Field;
-import java.security.GeneralSecurityException;
-import java.security.KeyFactory;
-import java.security.PrivateKey;
-import java.security.spec.PKCS8EncodedKeySpec;
 import java.util.Arrays;
-import java.util.Base64;
 import java.util.Collection;
 import java.util.Collections;
-import java.util.Comparator;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
 import java.util.stream.Collectors;
-import javax.annotation.PostConstruct;
-import javax.crypto.Cipher;
 
-import cn.jiguang.common.ClientConfig;
 import cn.jiguang.common.ServiceHelper;
-import cn.jiguang.common.connection.ApacheHttpClient;
-import cn.jiguang.common.resp.APIConnectionException;
 import cn.jiguang.common.resp.APIRequestException;
 import cn.jmessage.api.JMessageClient;
 import cn.jmessage.api.common.model.RegisterInfo;
@@ -28,14 +16,13 @@ import cn.jmessage.api.user.UserInfoResult;
 import cn.jmessage.api.user.UserStateListResult;
 import cn.jmessage.api.user.UserStateResult;
 import cn.jpush.api.JPushClient;
-import cn.jpush.api.push.CIDResult;
-import cn.jpush.api.push.PushClient;
 import cn.jpush.api.push.PushResult;
 import cn.jpush.api.push.model.BatchPushResult;
 import cn.jpush.api.push.model.Message;
 import cn.jpush.api.push.model.PushPayload;
 import cn.jpush.api.push.model.notification.Notification;
 import cn.jpush.api.report.ReceivedsResult;
+import com.chelvc.framework.base.context.ApplicationContextHolder;
 import com.chelvc.framework.base.context.LoggingContextHolder;
 import com.chelvc.framework.common.model.Period;
 import com.chelvc.framework.common.model.Platform;
@@ -45,7 +32,6 @@ import com.chelvc.framework.common.util.ObjectUtils;
 import com.chelvc.framework.common.util.StringUtils;
 import com.chelvc.framework.jpush.config.JPushProperties;
 import com.chelvc.framework.jpush.context.JPushContextHolder;
-import com.google.common.collect.ImmutableMap;
 import lombok.NonNull;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
@@ -68,11 +54,6 @@ import org.springframework.web.client.RestTemplate;
 @Component
 @RequiredArgsConstructor(onConstructor = @__(@Autowired))
 public class DefaultJPushHandler implements JPushHandler {
-    /**
-     * 极光令牌验证地址
-     */
-    private static final String TOKEN2MOBILE_URL = "https://api.verification.jpush.cn/v1/web/loginTokenVerify";
-
     /**
      * 获取消息地址
      */
@@ -95,72 +76,10 @@ public class DefaultJPushHandler implements JPushHandler {
      */
     private static final String GET_HISTORY_MESSAGE_URL = "https://report.im.jpush.cn/v2/users/%s/messages?cursor=%s";
 
+    private final JPushClient pushClient;
+    private final JMessageClient messageClient;
     private final RestTemplate restTemplate;
     private final JPushProperties properties;
-    private PrivateKey privateKey;
-    private JPushClient pushClient;
-    private JMessageClient messageClient;
-
-    @PostConstruct
-    public void initialize() throws GeneralSecurityException {
-        // 初始化登录认证配置
-        JPushProperties.Login login = this.properties.getLogin();
-        if (login != null && StringUtils.notEmpty(login.getSecret())) {
-            // 初始化私钥
-            byte[] secret = Base64.getDecoder().decode(login.getSecret());
-            PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(secret);
-            this.privateKey = KeyFactory.getInstance("RSA").generatePrivate(keySpec);
-        }
-
-        // 初始化消息推送配置
-        JPushProperties.Push push = this.properties.getPush();
-        if (push != null && StringUtils.notEmpty(push.getAppkey()) && StringUtils.notEmpty(push.getSecret())) {
-            // 初始化推送客户端实例
-            this.pushClient = new JPushClient(push.getSecret(), push.getAppkey()) {
-                {
-                    Field field = ObjectUtils.getField(JPushClient.class, "_pushClient");
-                    ObjectUtils.setValue(this, field, new PushClient(push.getSecret(), push.getAppkey()) {
-                        @Override
-                        public CIDResult getCidList(int count, String type) throws APIConnectionException,
-                                APIRequestException {
-                            // 对批量推送CID排序,确保推送结果顺序与发送数据顺序一致
-                            CIDResult result = super.getCidList(count, type);
-                            if (result != null && !CollectionUtils.isEmpty(result.cidlist)) {
-                                result.cidlist.sort(Comparator.naturalOrder());
-                            }
-                            return result;
-                        }
-                    });
-                }
-            };
-
-            // 初始化消息客户端实例
-            this.messageClient = new JMessageClient(push.getAppkey(), push.getSecret());
-            this.messageClient.setHttpClient(new ApacheHttpClient(
-                    ServiceHelper.getBasicAuthorization(push.getAppkey(), push.getSecret()),
-                    null,
-                    ClientConfig.getInstance()
-            ));
-        }
-    }
-
-    /**
-     * 获取推送客户端实例
-     *
-     * @return 推送客户端实例
-     */
-    private JPushClient getPushClient() {
-        return AssertUtils.nonnull(this.pushClient, () -> "JPush client has not been initialized");
-    }
-
-    /**
-     * 获取消息客户端实例
-     *
-     * @return 消息客户端实例
-     */
-    private JMessageClient getMessageClient() {
-        return AssertUtils.nonnull(this.messageClient, () -> "JMessage client has not been initialized");
-    }
 
     /**
      * 获取聊天消息
@@ -169,10 +88,10 @@ public class DefaultJPushHandler implements JPushHandler {
      * @return 聊天消息
      */
     private ChatMessage getChatMessages(String url) {
-        String appkey = ObjectUtils.ifNull(this.properties.getPush(), JPushProperties.Push::getAppkey);
-        String secret = ObjectUtils.ifNull(this.properties.getPush(), JPushProperties.Push::getSecret);
         HttpHeaders headers = new HttpHeaders();
-        headers.add("Authorization", ServiceHelper.getBasicAuthorization(appkey, secret));
+        headers.add("Authorization", ServiceHelper.getBasicAuthorization(
+                this.properties.getId(), this.properties.getSecret()
+        ));
         headers.setContentType(MediaType.APPLICATION_JSON);
         HttpEntity<?> entity = new HttpEntity<>(headers);
         try {
@@ -183,48 +102,13 @@ public class DefaultJPushHandler implements JPushHandler {
         }
     }
 
-    @Override
-    public String token2mobile(@NonNull String token) {
-        PrivateKey key = AssertUtils.nonnull(this.privateKey, () -> "Private key has not been initialized");
-
-        // 根据令牌获取手机号密文
-        Map<String, String> parameters = ImmutableMap.of("loginToken", token);
-        String authorization = ObjectUtils.ifNull(this.properties.getLogin(), JPushProperties.Login::getAuthorization);
-        HttpHeaders headers = new HttpHeaders();
-        headers.add("Authorization", authorization);
-        headers.setContentType(MediaType.APPLICATION_JSON);
-        HttpEntity<?> entity = new HttpEntity<>(parameters, headers);
-        JPushMobile response;
-        try {
-            response = this.restTemplate.exchange(
-                    TOKEN2MOBILE_URL, HttpMethod.POST, entity, JPushMobile.class
-            ).getBody();
-        } catch (Exception e) {
-            LoggingContextHolder.warn(log, e);
-            return null;
-        }
-        if (response == null || response.getCode() == null || response.getCode() != 8000) {
-            LoggingContextHolder.warn(log, response);
-            return null;
-        }
-
-        // 解码手机号
-        try {
-            Cipher cipher = Cipher.getInstance("RSA");
-            cipher.init(Cipher.DECRYPT_MODE, key);
-            return new String(cipher.doFinal(Base64.getDecoder().decode(response.getPhone())));
-        } catch (GeneralSecurityException e) {
-            throw new RuntimeException(e);
-        }
-    }
-
     @Override
     public boolean register(@NonNull RegisterInfo... registrations) {
         if (registrations.length == 0) {
             return false;
         }
         try {
-            this.getMessageClient().registerUsers(registrations);
+            this.messageClient.registerUsers(registrations);
         } catch (Exception e) {
             int code;
             if (e instanceof APIRequestException
@@ -245,12 +129,12 @@ public class DefaultJPushHandler implements JPushHandler {
     @Override
     public long push(@NonNull PushPayload payload) {
         // 针对生产环境IOS推送,需要设置apnsProduction为true
-        if (JPushContextHolder.isProduction()) {
+        if (ApplicationContextHolder.isProduction()) {
             payload.resetOptionsApnsProduction(true);
         }
         PushResult result;
         try {
-            result = this.getPushClient().sendPush(payload);
+            result = this.pushClient.sendPush(payload);
         } catch (Exception e) {
             LoggingContextHolder.warn(log, e);
             return 0;
@@ -321,13 +205,13 @@ public class DefaultJPushHandler implements JPushHandler {
     public BatchPushResult push(@NonNull List<PushPayload> payloads) {
         AssertUtils.nonempty(payloads, () -> "payloads must not be empty");
         // 针对生产环境IOS推送,需要设置apnsProduction为true
-        if (JPushContextHolder.isProduction()) {
+        if (ApplicationContextHolder.isProduction()) {
             payloads.forEach(payload -> payload.resetOptionsApnsProduction(true));
         }
 
         // 批量推送消息
         try {
-            return this.getPushClient().batchSendPushByAlias(payloads);
+            return this.pushClient.batchSendPushByAlias(payloads);
         } catch (Exception e) {
             LoggingContextHolder.warn(log, e);
             return null;
@@ -346,7 +230,7 @@ public class DefaultJPushHandler implements JPushHandler {
         }
         ReceivedsResult result;
         try {
-            result = this.getPushClient().getReceivedsDetail(ids);
+            result = this.pushClient.getReceivedsDetail(ids);
         } catch (Exception e) {
             LoggingContextHolder.warn(log, e);
             return Collections.emptyList();
@@ -375,7 +259,7 @@ public class DefaultJPushHandler implements JPushHandler {
     @Override
     public UserInfoResult getUserInfo(@NonNull String username) {
         try {
-            return this.getMessageClient().getUserInfo(username);
+            return this.messageClient.getUserInfo(username);
         } catch (Exception e) {
             LoggingContextHolder.warn(log, e);
             return null;
@@ -385,7 +269,7 @@ public class DefaultJPushHandler implements JPushHandler {
     @Override
     public UserStateResult getUserState(@NonNull String username) {
         try {
-            return this.getMessageClient().getUserState(username);
+            return this.messageClient.getUserState(username);
         } catch (Exception e) {
             LoggingContextHolder.warn(log, e);
             return null;
@@ -398,7 +282,7 @@ public class DefaultJPushHandler implements JPushHandler {
             return new UserStateListResult[0];
         }
         try {
-            return this.getMessageClient().getUsersState(usernames);
+            return this.messageClient.getUsersState(usernames);
         } catch (Exception e) {
             LoggingContextHolder.warn(log, e);
             return new UserStateListResult[0];

+ 0 - 8
framework-jpush/src/main/java/com/chelvc/framework/jpush/JPushHandler.java

@@ -23,14 +23,6 @@ import com.chelvc.framework.common.model.Platform;
  * @date 2024/1/30
  */
 public interface JPushHandler {
-    /**
-     * 根据令牌获取手机号
-     *
-     * @param token 令牌标识
-     * @return 手机号
-     */
-    String token2mobile(String token);
-
     /**
      * 账号注册
      *

+ 0 - 35
framework-jpush/src/main/java/com/chelvc/framework/jpush/JPushMobile.java

@@ -1,35 +0,0 @@
-package com.chelvc.framework.jpush;
-
-import java.io.Serializable;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-import lombok.experimental.SuperBuilder;
-
-/**
- * JPush手机号信息
- *
- * @author Woody
- * @date 2024/1/30
- */
-@Data
-@SuperBuilder
-@NoArgsConstructor
-@AllArgsConstructor
-public class JPushMobile implements Serializable {
-    /**
-     * 结果码
-     */
-    private Integer code;
-
-    /**
-     * 手机号密文
-     */
-    private String phone;
-
-    /**
-     * 结果信息
-     */
-    private String content;
-}

+ 64 - 0
framework-jpush/src/main/java/com/chelvc/framework/jpush/config/JPushConfigurer.java

@@ -0,0 +1,64 @@
+package com.chelvc.framework.jpush.config;
+
+import java.lang.reflect.Field;
+import java.util.Comparator;
+
+import cn.jiguang.common.ClientConfig;
+import cn.jiguang.common.ServiceHelper;
+import cn.jiguang.common.connection.ApacheHttpClient;
+import cn.jiguang.common.resp.APIConnectionException;
+import cn.jiguang.common.resp.APIRequestException;
+import cn.jmessage.api.JMessageClient;
+import cn.jpush.api.JPushClient;
+import cn.jpush.api.push.CIDResult;
+import cn.jpush.api.push.PushClient;
+import com.chelvc.framework.common.util.ObjectUtils;
+import lombok.RequiredArgsConstructor;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.util.CollectionUtils;
+
+/**
+ * 极光推送配置
+ *
+ * @author Woody
+ * @date 2024/1/30
+ */
+@Configuration
+@RequiredArgsConstructor(onConstructor = @__(@Autowired))
+public class JPushConfigurer {
+    private final JPushProperties properties;
+
+    @Bean
+    public JPushClient jPushClient() {
+        return new JPushClient(this.properties.getSecret(), this.properties.getId()) {
+            {
+                Field field = ObjectUtils.getField(JPushClient.class, "_pushClient");
+                ObjectUtils.setValue(this, field, new PushClient(properties.getSecret(), properties.getId()) {
+                    @Override
+                    public CIDResult getCidList(int count, String type) throws APIConnectionException,
+                            APIRequestException {
+                        // 对批量推送CID排序,确保推送结果顺序与发送数据顺序一致
+                        CIDResult result = super.getCidList(count, type);
+                        if (result != null && !CollectionUtils.isEmpty(result.cidlist)) {
+                            result.cidlist.sort(Comparator.naturalOrder());
+                        }
+                        return result;
+                    }
+                });
+            }
+        };
+    }
+
+    @Bean
+    public JMessageClient jMessageClient() {
+        JMessageClient client = new JMessageClient(this.properties.getId(), this.properties.getSecret());
+        client.setHttpClient(new ApacheHttpClient(
+                ServiceHelper.getBasicAuthorization(this.properties.getId(), this.properties.getSecret()),
+                null,
+                ClientConfig.getInstance()
+        ));
+        return client;
+    }
+}

+ 18 - 55
framework-jpush/src/main/java/com/chelvc/framework/jpush/config/JPushProperties.java

@@ -15,76 +15,39 @@ import org.springframework.context.annotation.Configuration;
 @ConfigurationProperties("jpush")
 public class JPushProperties {
     /**
-     * 是否是生产环境
+     * 应用标识
      */
-    private boolean production;
+    private String id;
 
     /**
-     * 消息推送配置
+     * 应用密钥
      */
-    private final Push push = new Push();
+    private String secret;
 
     /**
-     * 登录认证配置
+     * 华为配置
      */
-    private final Login login = new Login();
+    private final Attribute huawei = new Attribute();
 
     /**
-     * 消息推送配置
+     * 荣耀配置
      */
-    @Data
-    public static class Push {
-        /**
-         * 应用标识
-         */
-        private String appkey;
-
-        /**
-         * 编解码密钥
-         */
-        private String secret;
-
-        /**
-         * 华为配置
-         */
-        private final Attribute huawei = new Attribute();
-
-        /**
-         * 荣耀配置
-         */
-        private final Attribute honor = new Attribute();
+    private final Attribute honor = new Attribute();
 
-        /**
-         * 小米配置
-         */
-        private final Attribute xiaomi = new Attribute();
-
-        /**
-         * OPPO配置
-         */
-        private final Attribute oppo = new Attribute();
-
-        /**
-         * VIVO配置
-         */
-        private final Attribute vivo = new Attribute();
-    }
+    /**
+     * 小米配置
+     */
+    private final Attribute xiaomi = new Attribute();
 
     /**
-     * 登录认证配置
+     * OPPO配置
      */
-    @Data
-    public static class Login {
-        /**
-         * 编解码密钥
-         */
-        private String secret;
+    private final Attribute oppo = new Attribute();
 
-        /**
-         * 认证信息
-         */
-        private String authorization;
-    }
+    /**
+     * VIVO配置
+     */
+    private final Attribute vivo = new Attribute();
 
     /**
      * 属性配置

+ 6 - 36
framework-jpush/src/main/java/com/chelvc/framework/jpush/context/JPushContextHolder.java

@@ -35,39 +35,9 @@ public final class JPushContextHolder {
      */
     private static Options ANDROID_OPTIONS;
 
-    /**
-     * 配置属性实例
-     */
-    private static JPushProperties PROPERTIES;
-
     private JPushContextHolder() {
     }
 
-    /**
-     * 获取配置属性
-     *
-     * @return 配置属性实例
-     */
-    public static JPushProperties getProperties() {
-        if (PROPERTIES == null) {
-            synchronized (JPushProperties.class) {
-                if (PROPERTIES == null) {
-                    PROPERTIES = ApplicationContextHolder.getBean(JPushProperties.class);
-                }
-            }
-        }
-        return PROPERTIES;
-    }
-
-    /**
-     * 判断是否是生产环境
-     *
-     * @return true/false
-     */
-    public static boolean isProduction() {
-        return getProperties().isProduction();
-    }
-
     /**
      * 将对象转换成别名
      *
@@ -156,13 +126,13 @@ public final class JPushContextHolder {
         if (ANDROID_OPTIONS == null) {
             synchronized (Options.class) {
                 if (ANDROID_OPTIONS == null) {
-                    JPushProperties.Push push = getProperties().getPush();
+                    JPushProperties properties = ApplicationContextHolder.getBean(JPushProperties.class);
                     ANDROID_OPTIONS = Options.newBuilder().setThirdPartyChannelV2(ImmutableMap.of(
-                            "huawei", initializeAndroidChannel(push.getHuawei()),
-                            "honor", initializeAndroidChannel(push.getHonor()),
-                            "xiaomi", initializeAndroidChannel(push.getXiaomi()),
-                            "oppo", initializeAndroidChannel(push.getOppo()),
-                            "vivo", initializeAndroidChannel(push.getVivo())
+                            "huawei", initializeAndroidChannel(properties.getHuawei()),
+                            "honor", initializeAndroidChannel(properties.getHonor()),
+                            "xiaomi", initializeAndroidChannel(properties.getXiaomi()),
+                            "oppo", initializeAndroidChannel(properties.getOppo()),
+                            "vivo", initializeAndroidChannel(properties.getVivo())
                     )).build();
                 }
             }