Sfoglia il codice sorgente

裂变计划redis

(cherry picked from commit e534b2291bbba7383f5d14a515bb5adc6b0facf0)
MOKASZ\lw12420 2 anni fa
parent
commit
9978bee368

+ 5 - 1
launch-admin/pom.xml

@@ -60,7 +60,11 @@
             <artifactId>hutool-all</artifactId>
             <version>5.3.7</version>
         </dependency>
-
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+            <version>2.12.3</version>
+        </dependency>
         <dependency>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>

+ 197 - 0
launch-admin/src/main/java/com/webflux/launchadmin/mysql/task/SyncPlanNewToRedis.java

@@ -0,0 +1,197 @@
+package com.webflux.launchadmin.mysql.task;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+import com.plumelog.core.util.LogExceptionStackTrace;
+import com.webflux.launchadmin.global.BaseException;
+import com.fasterxml.jackson.databind.module.SimpleModule;
+import com.webflux.launchadmin.mysql.entity.planNew.PlanNew;
+import com.weblux.launchredis.utils.FissionRedisKey;
+import jakarta.annotation.Resource;
+import lombok.extern.slf4j.Slf4j;
+import net.javacrumbs.shedlock.spring.annotation.SchedulerLock;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.data.r2dbc.core.R2dbcEntityTemplate;
+import org.springframework.data.redis.core.ReactiveRedisTemplate;
+import org.springframework.data.relational.core.query.Criteria;
+import org.springframework.data.relational.core.query.Query;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+import reactor.core.publisher.Flux;
+import reactor.core.publisher.Mono;
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+
+import java.io.IOException;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class SyncPlanNewToRedis {
+    @Resource
+    private R2dbcEntityTemplate template;
+    @Resource
+    private ReactiveRedisTemplate<String,String> reactiveRedisTemplate;
+
+    /**
+     * SELECT GROUP_CONCAT(COLUMN_NAME SEPARATOR ', ') AS column_names
+     * FROM information_schema.COLUMNS
+     * WHERE TABLE_NAME = 'plan_new' AND TABLE_SCHEMA = 'wx_share_test';
+     */
+    //    String column="plan_new_id, name,  type, code, group_id, " +
+    //            "poster_template_id, page_show, page_line, count, list_audio_id, ret_audio_id, link, is_add_qun, " +
+    //            "background_group_id, home_page_id, top_adv_num, bottom_adv_num, return_loop_id, background_group_qs_id, " +
+    //            "top_adv_bl, bottom_adv_bl, return_loop_bl, group_Id_qs, baidu_dot, background_group_id_new_add, preview_url," +
+    //            " redirect_type, redirect_plan_id, import_domain, landing_page_domain, transfer_page_domain, transfer_page_bl," +
+    //            " backgroup_domain, list_button, group_list_display";
+    /**
+     *同步裂变计划
+     */
+    @Scheduled(cron="0 */1 * * * ?")
+    @SchedulerLock(name = "launch:SyncFissionPlan:syncPlanNew", lockAtLeastFor = "PT5S", lockAtMostFor = "PT15M")
+    public void syncFissionPlan(){
+        Mono<List<PlanNew>> listMono = template.select(PlanNew.class).all().collectList();
+        listMono.flatMap(list -> {
+            List<String> collect = list.stream().map(PlanNew::code).collect(Collectors.toList());
+            Mono<List<String>> listMono1 = reactiveRedisTemplate
+                    .opsForSet()
+                    .members(FissionRedisKey.PLAN_NEW_INFO_SET).collectList()
+                    .switchIfEmpty(Mono.just(List.of()));
+            return Mono.zip(Mono.just(collect),listMono1,Mono.just(list)).flatMap(tupleN->{
+                var mids = tupleN.getT1();
+                var rids = tupleN.getT2();
+                var planNews = tupleN.getT3();
+                // +
+                List<String> addIds = mids.stream().filter(mid -> !rids.contains(mid)).collect(Collectors.toList());
+                Mono<Void> addMono=Mono.empty();
+                if (!addIds.isEmpty()) {
+                    List<PlanNew> addPlanNew = planNews.stream().filter(f -> addIds.contains(f.code())).collect(Collectors.toList());
+                    if (!addPlanNew.isEmpty()) {
+                         addMono = Flux.fromIterable(addPlanNew)
+                                .flatMap(this::setRedisValue).then();
+                    }
+                }
+                // -
+                Mono<Void> then1 =Mono.empty();
+                List<String> removeIds = rids.stream().filter(rid -> !mids.contains(rid)).collect(Collectors.toList());
+                if (!removeIds.isEmpty()) {
+                    then1 = Flux.fromIterable(removeIds).flatMap(this::getDelete).then();
+                }
+              return  Mono.zip(addMono,then1).then();
+            }).then();
+        });
+    }
+
+    @NotNull
+    public Mono<Void> setRedisValue(PlanNew planNew) {
+        Mono<Long> add = reactiveRedisTemplate.opsForSet().add(FissionRedisKey.PLAN_NEW_INFO_SET, planNew.code());
+        String json= getPlanNewToString(planNew);
+        Mono<Boolean> set = reactiveRedisTemplate
+                .opsForValue()
+                .set(FissionRedisKey.PLAN_NEW_INFO_KEY + planNew.code(), json);
+       return set.then(add).then();
+    }
+
+    private String getPlanNewToString(PlanNew planNew) {
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.registerModule(new JavaTimeModule());
+        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
+        try {
+            // 将 record 转换为 JSON 字符串
+            return objectMapper.writeValueAsString(planNew);
+        } catch (JsonProcessingException e) {
+           throw new BaseException("PlanNew 将 record 转换为 JSON 字符串 异常:::"+e.getMessage());
+        }
+    }
+
+
+
+    @NotNull
+    public Mono<Void> getDelete(String code) {
+        Mono<Long> remove = reactiveRedisTemplate.opsForSet().remove(FissionRedisKey.PLAN_NEW_INFO_SET, code);
+        Mono<Boolean> delete = reactiveRedisTemplate.opsForValue().delete(FissionRedisKey.PLAN_NEW_INFO_KEY + code);
+        return remove.then(delete).then();
+    }
+
+    /**
+     * 通过code从数据库获取PlanNew并缓存redis
+     * @param code
+     * @return
+     */
+    public Mono<PlanNew> byCodeAndMysqlGetPlanNew(String code){
+        Mono<PlanNew> planNewMono = template
+                .selectOne(Query.query(Criteria.where("code").is(code)), PlanNew.class)//.columns(column.split(","))
+                .switchIfEmpty(Mono.error(new BaseException("计划code异常 返回结果为空"))) //Mono.error(new BaseException("查询海报模版 id:"+f.posterTemplateId()+"=>空"))
+                .onErrorResume(throwable -> Mono.error(new BaseException(throwable.getMessage())));
+       return planNewMono.flatMap(planNew -> {
+           Mono<Void> voidMono = setRedisValue(planNew);
+           return voidMono.then(Mono.just(planNew));
+        });
+    }
+
+    /**
+     * 通过redis获取缓存 空或失败 从mysql中取
+     * @param code
+     * @return
+     */
+    public Mono<PlanNew> byRedisGetPlanNewIfErByMysql(String code){
+      return   reactiveRedisTemplate.opsForValue()
+                 .get(FissionRedisKey.PLAN_NEW_INFO_KEY + code)
+                 .switchIfEmpty(Mono.just(""))
+              .onErrorResume(throwable -> Mono.error(new BaseException(throwable.getMessage())))
+              .flatMap(s -> {
+                     Mono<PlanNew> planNewMono;
+                     if(!"".equals(s)){
+                         try {
+                             PlanNew planNew = strParsePlanNew(s);
+                             planNewMono=Mono.just(planNew);
+                         }catch (Exception e){
+                             log.error("接口异常  {} e = {}","获取redis Value 解析PlanNew失败 暂时从Mysql获取内容" , LogExceptionStackTrace.erroStackTrace(e));
+                             planNewMono = byCodeAndMysqlGetPlanNew(code);
+                         }
+                     }else {
+                         planNewMono = byCodeAndMysqlGetPlanNew(code);
+                     }
+                     return planNewMono;
+         });
+    }
+    /**
+     * str 转PlanNew
+     * @param str
+     * @return
+     */
+    public PlanNew strParsePlanNew(String str) {
+        // 创建 ObjectMapper 实例并配置
+        ObjectMapper objectMapper = new ObjectMapper();
+        objectMapper.registerModule(new JavaTimeModule());
+        SimpleModule module = new SimpleModule();
+        module.addDeserializer(ZonedDateTime.class, new CustomZonedDateTimeDeserializer());
+        objectMapper.registerModule(module);
+            try {
+                // 将 JSON 字符串转换为 record
+                return objectMapper.readValue(str, PlanNew.class);
+            } catch (JsonProcessingException e) {
+                throw new BaseException(" 将 JSON字符串 转换为 PlanNew  异常:::"+e.getMessage());
+            }
+    }
+    // 自定义反序列化器
+    public static class CustomZonedDateTimeDeserializer extends JsonDeserializer<ZonedDateTime> {
+        private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        @Override
+        public ZonedDateTime deserialize(JsonParser p, DeserializationContext ctxt)
+                throws IOException, JsonProcessingException {
+            String date = p.getText();
+            LocalDateTime localDateTime = LocalDateTime.parse(date, FORMATTER);
+            // 使用系统默认时区,可以根据需要修改
+            return ZonedDateTime.of(localDateTime, ZoneId.systemDefault());
+        }
+    }
+}

+ 16 - 0
launch-redis/src/main/java/com/weblux/launchredis/utils/FissionRedisKey.java

@@ -0,0 +1,16 @@
+package com.weblux.launchredis.utils;
+
+/**
+ * 裂变redis-key
+ *
+ * @author:
+ * @date: 2024/7/12 10:06
+ */
+public class FissionRedisKey {
+
+
+    //裂变计划缓存
+    public final static String PLAN_NEW_INFO = "sync_plan_new_info";
+    public final static String PLAN_NEW_INFO_SET = "sync_plan_new_info_set_ids";
+    public final static String PLAN_NEW_INFO_KEY = "sync_plan_new_info_";
+}