Jelajahi Sumber

doc:文档更新

wangzaijun 1 tahun lalu
induk
melakukan
258b91ecbd

+ 24 - 3
readme.md

@@ -1,5 +1,26 @@
-### 数据分析,详情页通用服务
+# 数据分析-详情页通用服务 (开发前必读)
+springboot3+redis+mybatis的一个标的详情页通用服务
 
+### 项目背景与目标
+> 本项目是一个使标的(基金、机构、经理、指数、组合)详情页最大化通用的项目,尽最大可能做到详情页所有组件接口不依赖
+> 非core库数据,如果存在依赖的其他外部数据源考虑是否业务相关。
+>
+> 目标实现实现可插拔、可扩展、易维护插件式组件,大家一起努力。
 
-##### 存在问题
-1、需要预刷新的数据(交易日、无风险利率)如何处理?在calc模块就刷新还是本服务,如果是本服务,那可能需要迁移咖啡因缓存到本服务,然后在calc去掉
+### 架构 以及 关注点
+- jdk17, graalvm 加快启动
+- springboot3.x 高版本的springboot框架,体验最新的功能
+- jakarta api迁移,springboot3.0以上的版本要求所有的Java EE api都要迁移到Jakarta。比如javax.servlet.Filter需要替换为jakarta.servlet.Filter
+- spring.factories 文件废弃,自动配置包位置有变化
+
+
+### 项目分包说明
+> 项目是一个DDD架构的简单落地,请遵循或尽量遵循如下规约,如有不足大家讨论补充
+- 1、目前项目分层主要为domain(领域层)、infrastructure(基础设施层)、application(应用层)、client(接口层,对外提供服务)
+- 2、分层说明:domain-所有都要用的共享对象;infrastructure-所有技术代码,mybatis、redis、mq、job、cache代码都要在这里实现(尽量做到domain通过依赖导致不依赖这些技术代码);application-应用层主要工作是一些领域服务、第三方服务的聚合,或者事件业务;client-对外提供接口服务,可以是门面、rest、rpc
+- 3、与calc计算服务的调用关系 参考 `BaseIndicatorServiceV2Impl` 食用,主要是调用calc提供的单例实例调用对应的方法获取结果
+
+
+##### 问题
+1、需要预刷新的数据(交易日、无风险利率)如何处理?
+在本服务提供job刷新到缓存

+ 4 - 11
src/main/java/com/smppw/analysis/application/dto/BaseParams.java

@@ -4,9 +4,11 @@ import com.smppw.common.pojo.enums.Frequency;
 import com.smppw.common.pojo.enums.NavType;
 import com.smppw.common.pojo.enums.RaiseType;
 import com.smppw.common.pojo.enums.TimeRange;
+import com.smppw.constants.Consts;
 import lombok.Getter;
 import lombok.Setter;
 
+import java.io.Serial;
 import java.io.Serializable;
 import java.util.List;
 
@@ -18,7 +20,8 @@ import java.util.List;
 @Setter
 @Getter
 public abstract class BaseParams implements Serializable {
-    private static final long serialVersionUID = 1L;
+    @Serial
+    private static final long serialVersionUID = Consts.DEFAULT_SERIAL_VERSION_UID;
 
     /**
      * 标的id,包括基金、机构和经理
@@ -61,16 +64,6 @@ public abstract class BaseParams implements Serializable {
      */
     private String endDate;
     /**
-     * 当前登录用户id
-     */
-    private Integer userId;
-
-    /**
-     * 是否计算费后:false-不计算,true-计算
-     */
-    private Boolean isExtract;
-
-    /**
      * 是否多标的,根据传参判断
      *
      * @return /

+ 0 - 4
src/main/java/com/smppw/analysis/application/dto/TrendParams.java

@@ -12,8 +12,4 @@ import lombok.Setter;
 @Getter
 public class TrendParams extends BaseParams {
 
-    /**
-     * 1: 展示 2:不展示
-     */
-    private String showTrade;
 }

+ 109 - 4
src/main/java/com/smppw/analysis/application/service/PerformanceService.java

@@ -8,6 +8,7 @@ import cn.hutool.core.util.NumberUtil;
 import cn.hutool.core.util.StrUtil;
 import com.smppw.analysis.application.dto.BaseParams;
 import com.smppw.analysis.application.dto.RateRiskIndicatorParams;
+import com.smppw.analysis.application.dto.TrendParams;
 import com.smppw.analysis.domain.service.BaseIndicatorServiceV2;
 import com.smppw.common.exception.APIException;
 import com.smppw.common.exception.DataException;
@@ -41,7 +42,11 @@ public class PerformanceService {
         this.baseIndicatorServiceV2 = baseIndicatorServiceV2;
     }
 
-    public Map<String, Object> rateRiskIndicators(RateRiskIndicatorParams params, List<Indicator> indicators, List<Indicator> geoIndicators) {
+    public Map<String, Object> calcIndicators(RateRiskIndicatorParams params) {
+        return this.calcIndicators(params, ListUtil.toList(Indicator.INDICATOR_TYPE_ARRAY), ListUtil.toList(Indicator.RISK_TABLE_EXCESS_INDICATOR_ARRAY));
+    }
+
+    public Map<String, Object> calcIndicators(RateRiskIndicatorParams params, List<Indicator> indicators, List<Indicator> geoIndicators) {
         try {
             // 1.参数处理
             this.checkParams(params);
@@ -60,7 +65,6 @@ public class PerformanceService {
             CalcMultipleSecMultipleTimeRangeIndicatorReq req = this.buildCalcReq(params, indicators, geoIndicators, DateIntervalType.CustomInterval, null);
             req.setRiskOfFreeId(riskOfFreeId);
             req.setRiskOfFreeValue(riskOfFreeValue);
-            req.setIfExtract(params.getIsExtract() != null && params.getIsExtract());
 
             // 2.指标计算
             Map<String, List<IndicatorCalcPropertyDto>> indicator = this.baseIndicatorServiceV2.calcMultipleSecMultipleTimeRangeIndicator(req);
@@ -108,6 +112,83 @@ public class PerformanceService {
         return MapUtil.newHashMap();
     }
 
+    protected CommonData<Map<String, List<Map<String, Object>>>> handleTrends(TrendParams params, List<TrendType> trendTypes, List<TrendType> indexTrendTypes, String masterId) {
+        // 1、参数处理
+        this.checkParams(params);
+        boolean multiSec = params.multiSec();
+        List<String> refIds = params.getFundId();
+        List<String> secIds = this.getSecIdsByParams(params);
+        List<String> indexIds = CollectionUtil.subtractToList(secIds, refIds);
+
+        // 时段参数构建
+        DateIntervalDto dateInterval = this.buildDateIntervalByParams(params, DateIntervalType.CustomInterval, null);
+        Map<String, String> benchmarkIdMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            if (StrUtil.isBlank(params.getBenchmarkId())) {
+                continue;
+            }
+            benchmarkIdMap.put(refId, params.getBenchmarkId());
+        }
+
+        // 计算走势图
+        Map<String, List<IndicatorCalcPropertyDto>> trendMap = this.baseIndicatorServiceV2.getMultipleSecTrend(refIds, benchmarkIdMap,
+                indexIds, dateInterval, params.getFrequency(), null, null, params.getRaiseType(), this.getOriginStrategy(params),
+                Visibility.Both, params.getNavType(), trendTypes);
+
+        // 结果处理,支持多标的
+        // 处理走势图
+        Map<String, List<Map<String, Object>>> dataListMap = MapUtil.newHashMap(true);
+        Map<String, List<Map<String, Object>>> indexDataListMap = MapUtil.newHashMap(true);
+        Map<String, Map<String, Object>> trendListMap = MapUtil.newHashMap(true);
+        Map<String, Map<String, Object>> indexTrendListMap = MapUtil.newHashMap(true);
+        for (String refId : refIds) {
+            IndicatorCalcPropertyDto dto = Optional.ofNullable(trendMap.get(refId)).filter(e -> !e.isEmpty()).map(e -> e.get(0)).orElse(null);
+            List<String> tempDateList = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getDateList).orElse(ListUtil.empty());
+            // 基金走势序列
+            Map<TrendType, List<Double>> tempTrendTypeListMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getSecData).map(IndicatorCalcSecDataDto::getTrendValueMap).orElse(MapUtil.empty());
+            trendListMap.put(refId, MapUtil.<String, Object>builder().put("dates", tempDateList).put("trend", tempTrendTypeListMap).build());
+            dataListMap.put(refId, this.buildDateValue(tempDateList, tempTrendTypeListMap, trendTypes));
+            if (masterId == null && multiSec) {
+                // 多标的的 走势图 不绘制基准走势
+                continue;
+            }
+            // 指数净值和收益序列
+            Map<String, Map<TrendType, List<Double>>> tempIndexTrendTypeListMap = Optional.ofNullable(dto).map(IndicatorCalcPropertyDto::getIndexData).map(IndicatorCalcIndexDataDto::getIndexTrendValueMap).orElse(MapUtil.empty());
+            for (String indexId : indexIds) {
+                if (indexDataListMap.containsKey(indexId) && !indexId.equals(params.getBenchmarkId())) {
+                    continue;
+                }
+                indexTrendListMap.put(indexId, MapUtil.<String, Object>builder().put("dates", tempDateList).put("trend", tempIndexTrendTypeListMap.get(indexId)).build());
+                indexDataListMap.put(indexId, this.buildDateValue(tempDateList, tempIndexTrendTypeListMap.get(indexId), indexTrendTypes));
+            }
+        }
+//        Map<String, List<Map<String, Object>>> valuesMap = this.multiSecMergeDateValue(refIds, trendMap, dataListMap, trendTypes, multiSec);
+        Map<String, List<Map<String, Object>>> dataset = MapUtil.<String, List<Map<String, Object>>>builder().putAll(dataListMap).build();
+//        Map<String, String> productNameMapping = this.secId2NameService.query(secIds);
+//        Map<String, Object> extInfos = MapUtil.<String, Object>builder().put("endDate", params.getEndDate()).put("startDate", params.getStartDate()).build();
+//        if (masterId != null || !multiSec) {
+//            // 求基金和基准的年化收益率
+//            String fundId = refIds.get(0);
+//            Map<String, Object> map = trendListMap.get(fundId);
+//            Map<String, Object> indexMap = Optional.ofNullable(indexTrendListMap.get(params.getBenchmarkId())).orElse(MapUtil.newHashMap());
+//            List<String> dateList = MapUtil.get(map, "dates", List.class);
+//            Map<TrendType, List<Double>> trendTypeListMap = MapUtil.get(map, "trend", Map.class);
+//            Map<TrendType, List<Double>> indexTrendTypeListMap = Optional.ofNullable(MapUtil.get(indexMap, "trend", Map.class)).orElse(MapUtil.newHashMap());
+//            List<DateValue> dateValues = this.buildDateValue(dateList, trendTypeListMap.get(TrendType.Nav));
+//            List<DateValue> indexDateValues = this.buildDateValue(dateList, indexTrendTypeListMap.get(TrendType.OrigNav));
+//            Double annual = IndicatorFactory.getInstance().get(Indicator.AnnualReturn).calc(dateValues);
+//            Double annualBenchmark = IndicatorFactory.getInstance().get(Indicator.AnnualReturn).calc(indexDateValues);
+//            // 求最大回撤和超额最大回撤,业绩走势图不返回
+//            Double maxDown = this.handleMaxAndMin(trendTypeListMap.get(TrendType.DrawdownTrend), (o1, o2) -> o1 > o2 ? o2 : o1);
+//            Double maxExtraDown = this.handleMaxAndMin(trendTypeListMap.get(TrendType.ExtraDrawdownTrend), (o1, o2) -> o1 > o2 ? o2 : o1);
+//            Map<String, Object> extInfos1 = MapUtil.<String, Object>builder("maxDown", maxDown).put("maxExtraDown", maxExtraDown)
+//                    .put("annual", annual).put("annualBenchmark", annualBenchmark).build();
+//            extInfos.putAll(extInfos1);
+//            dataset.putAll(indexDataListMap);
+//        }
+        return CommonData.<Map<String, List<Map<String, Object>>>>builder().dataset(dataset).build();
+    }
+
     /**
      * 构建指标计算参数
      *
@@ -139,13 +220,11 @@ public class PerformanceService {
                 .visibility(Visibility.Both)
                 .dataFrequency(params.getFrequency())
                 .navType(params.getNavType())
-                .userId(params.getUserId())
                 .secDateIntervalDtoListMap(dateIntervalMap)
                 .indicatorList(indicators)
                 .geoExtraindicatorList(geoIndicators)
                 .ifAnnualize(true)
                 .calcIndexRetIndicatorValue(true)
-                .ifExtract(params.getIsExtract() != null && params.getIsExtract())
                 .ifConvertPerformanceConsistencyWord(true).build();
     }
 
@@ -279,4 +358,30 @@ public class PerformanceService {
         }
         return result;
     }
+
+    /**
+     * 构建日期值对象
+     *
+     * @param dateList         日期序列
+     * @param trendTypeListMap 走势图数据
+     * @param trendTypes       走势图类型列表
+     * @return /
+     */
+    private List<Map<String, Object>> buildDateValue(List<String> dateList, Map<TrendType, List<Double>> trendTypeListMap, List<TrendType> trendTypes) {
+        List<Map<String, Object>> dataList = ListUtil.list(true);
+        for (int i = 0; i < dateList.size(); i++) {
+            Map<String, Object> temp = MapUtil.<String, Object>builder("date", dateList.get(i)).build();
+            for (TrendType trendType : trendTypes) {
+                List<Double> doubles = trendTypeListMap.get(trendType);
+                Object value = null;
+                try {
+                    value = i <= doubles.size() ? doubles.get(i) : null;
+                } catch (Exception ignored) {
+                }
+                temp.put(StrUtil.toCamelCase(trendType.name()), value);
+            }
+            dataList.add(temp);
+        }
+        return dataList;
+    }
 }

+ 2 - 4
src/main/java/com/smppw/analysis/interfaces/FundApi.java

@@ -1,9 +1,7 @@
-package com.smppw.analysis.interfaces;
+package com.smppw.analysis.client;
 
-import cn.hutool.core.collection.ListUtil;
 import com.smppw.analysis.application.dto.RateRiskIndicatorParams;
 import com.smppw.analysis.application.service.PerformanceService;
-import com.smppw.common.pojo.enums.Indicator;
 import com.smppw.common.pojo.vo.ResultVo;
 import org.springframework.web.bind.annotation.GetMapping;
 import org.springframework.web.bind.annotation.RequestMapping;
@@ -22,7 +20,7 @@ public class FundApi {
 
     @GetMapping("/indicators")
     public ResultVo<Map<String, Object>> indicator(RateRiskIndicatorParams params) {
-        Map<String, Object> data = this.performanceService.rateRiskIndicators(params, ListUtil.toList(Indicator.INDICATOR_TYPE_ARRAY), ListUtil.toList(Indicator.RISK_TABLE_EXCESS_INDICATOR_ARRAY));
+        Map<String, Object> data = this.performanceService.calcIndicators(params);
         return ResultVo.ok(data);
     }
 }

+ 1 - 1
src/main/java/com/smppw/analysis/domain/service/BaseIndicatorServiceV2.java

@@ -15,6 +15,6 @@ public interface BaseIndicatorServiceV2 {
 
     Map<String, List<IndicatorCalcPropertyDto>> getMultipleSecTrend(List<String> mainSecIdList, Map<String, String> secBenchmarkIdMap, List<String> indexIdList,
                                                                     DateIntervalDto dateIntervalDto, Frequency frequency, BigDecimal fixedIncome, BigDecimal initValue, RaiseType raiseType,
-                                                                    IStrategy strategy, Visibility visibility, NavType navType, List<TrendType> trendTypeV2List, Boolean ifExtract, Integer userId);
+                                                                    IStrategy strategy, Visibility visibility, NavType navType, List<TrendType> trendTypeV2List);
 
 }

+ 1 - 1
src/main/java/com/smppw/analysis/domain/service/impl/BaseIndicatorServiceV2Impl.java

@@ -55,7 +55,7 @@ public class BaseIndicatorServiceV2Impl implements BaseIndicatorServiceV2 {
     public Map<String, List<IndicatorCalcPropertyDto>> getMultipleSecTrend(List<String> mainSecIdList, Map<String, String> secBenchmarkIdMap,
                                                                            List<String> indexIdList, DateIntervalDto dateIntervalDto, Frequency frequency,
                                                                            BigDecimal fixedIncome, BigDecimal initValue, RaiseType raiseType, IStrategy strategy,
-                                                                           Visibility visibility, NavType navType, List<TrendType> trendTypeV2List, Boolean ifExtract, Integer userId) {
+                                                                           Visibility visibility, NavType navType, List<TrendType> trendTypeV2List) {
         List<String> benchmarkIdList = secBenchmarkIdMap.values().stream().distinct().collect(Collectors.toList());
         CurveType curveType = CurveType.getCurveType(raiseType, strategy);
         Map<String, List<DateValue>> allNavMap = navService.getSecIdDateValueNavListMapFromRedisAndDB(mainSecIdList, benchmarkIdList, indexIdList,

+ 23 - 2
src/main/java/com/smppw/analysis/domain/service/impl/NavServiceImpl.java

@@ -3,7 +3,6 @@ package com.smppw.analysis.domain.service.impl;
 import com.smppw.analysis.domain.dao.*;
 import com.smppw.analysis.domain.service.NavService;
 import com.smppw.analysis.domain.service.SecTypeService;
-import com.smppw.analysis.infrastructure.utils.DateValueUtil;
 import com.smppw.common.pojo.dto.DateValue;
 import com.smppw.common.pojo.dto.NavDto;
 import com.smppw.common.pojo.enums.Frequency;
@@ -263,12 +262,34 @@ public class NavServiceImpl implements NavService {
         for (Map.Entry<String, List<NavDto>> fundIdNavDtoListEntry : secIdNavDtoListMap.entrySet()) {
             List<NavDto> navDtoList = fundIdNavDtoListEntry.getValue();
             String fundId = fundIdNavDtoListEntry.getKey();
-            List<DateValue> dateValueList = DateValueUtil.convertNavList(navDtoList, navType);
+            List<DateValue> dateValueList = this.convertNavList(navDtoList, navType);
             secIdDateValueListMap.put(fundId, dateValueList);
         }
         return secIdDateValueListMap;
     }
 
+    private List<DateValue> convertNavList(List<NavDto> navDtoList, NavType navType) {
+        List<DateValue> dateValueList = new ArrayList<>();
+        for (NavDto navDto : navDtoList) {
+            DateValue dateValue = new DateValue();
+            dateValue.setDate(navDto.getPriceDate());
+            if (NavType.WithdrawalNav == navType) {
+                dateValue.setValue(navDto.getCumulativeNavWithdrawal() != null ? navDto.getCumulativeNavWithdrawal().doubleValue() : null);
+            } else if (NavType.OriginalNav == navType) {
+                dateValue.setValue(navDto.getOriginalNav() != null ? navDto.getOriginalNav().doubleValue() : null);
+            } else if (NavType.All == navType) {
+                dateValue.setValue(navDto.getOriginalNav() != null ? navDto.getOriginalNav().doubleValue() : null);
+                dateValue.setOriginalNav(navDto.getOriginalNav() != null ? navDto.getOriginalNav() : null);
+                dateValue.setCumulativeNav(navDto.getCumulativeNav() != null ? navDto.getCumulativeNav() : null);
+                dateValue.setCumulativeNavWithdrawal(navDto.getCumulativeNavWithdrawal() != null ? navDto.getCumulativeNavWithdrawal() : null);
+            } else {
+                dateValue.setValue(navDto.getCumulativeNav() != null ? navDto.getCumulativeNav().doubleValue() : null);
+            }
+            dateValueList.add(dateValue);
+        }
+        return dateValueList;
+    }
+
 //    private void cacheNavDataToRedis(List<String> dbSecIds, Map<String, String> secKeyMap, Integer curveType, Integer strategy, Visibility visibility, NavType navType, Map<String, Frequency> secFrequencyMap) {
 //
 ////        if (extractNavServiceReq != null && extractNavServiceReq.isIfExtract()) {

+ 712 - 0
src/main/java/com/smppw/analysis/infrastructure/components/RedisService.java

@@ -0,0 +1,712 @@
+package com.smppw.analysis.infrastructure.components;
+
+import cn.hutool.core.map.MapUtil;
+import cn.hutool.core.util.StrUtil;
+import cn.hutool.json.JSONUtil;
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.hash.HashMapper;
+import org.springframework.data.redis.hash.Jackson2HashMapper;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+@Component
+public class RedisService {
+    private final RedisTemplate<String, Object> _redisTemplate;
+    private final HashOperations<String, String, Object> _hashOperations;
+    private final HashMapper<Object, String, Object> _hashMapper;
+
+    public RedisService(RedisTemplate<String, Object> _redisTemplate) {
+        this._redisTemplate = _redisTemplate;
+        this._hashOperations = _redisTemplate.opsForHash();
+        this._hashMapper = new Jackson2HashMapper(true);
+    }
+
+
+    // =============================common============================
+
+    /**
+     * 指定缓存失效时间
+     *
+     * @param key  键
+     * @param time 时间(秒)
+     * @return /
+     */
+    public boolean expire(String key, long time) {
+        try {
+            if (time > 0) {
+                _redisTemplate.expire(key, time, TimeUnit.SECONDS);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 根据key 获取过期时间
+     *
+     * @param key 键 不能为null
+     * @return 时间(秒) 返回0代表为永久有效
+     */
+    public Long getExpire(String key) {
+        return _redisTemplate.getExpire(key, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 判断key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public Boolean hasKey(String key) {
+        if (StrUtil.isBlank(key)) {
+            return false;
+        }
+        return _redisTemplate.hasKey(key);
+    }
+
+    /**
+     * 删除缓存
+     *
+     * @param key 可以传一个值 或多个
+     */
+    @SuppressWarnings("unchecked")
+    public void delete(String... key) {
+        if (key != null && key.length > 0) {
+            if (key.length == 1) {
+                _redisTemplate.delete(key[0]);
+            } else {
+                _redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
+            }
+        }
+    }
+    // ============================String=============================
+
+    /**
+     * 普通缓存获取
+     *
+     * @param key 键
+     * @return 值
+     */
+    public Object get(String key) {
+        return key == null ? null : _redisTemplate.opsForValue().get(key);
+    }
+
+    /**
+     * 获取hashKey对应的所有键值
+     *
+     * @param key 键
+     * @return 对应的多个键值
+     */
+    public <T> T get(String key, Class<T> pValClass) {
+        Object rtn = _redisTemplate.opsForValue().get(key);
+        if (null == rtn) {
+            return null;
+        }
+        if (rtn.getClass().equals(pValClass)) {
+            return (T) rtn;
+        } else if (rtn instanceof Map) {
+            return JSONUtil.toBean(JSONUtil.toJsonStr(rtn), pValClass);
+        } else if (rtn instanceof String) {
+            return JSONUtil.toBean((String) rtn, pValClass);
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * 普通缓存放入
+     *
+     * @param key   键
+     * @param value 值
+     * @return true成功 false失败
+     */
+    public boolean set(String key, Object value) {
+        try {
+            _redisTemplate.opsForValue().set(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * Description: 如果key存在, 则返回false, 如果不存在,
+     * 则将key=value放入redis中, 并返回true
+     *
+     * @param
+     * @return
+     * @author: bixuejun(bxjgood @ 163.com)
+     * @date: 2021/11/26 14:36
+     */
+    public Boolean setIfAbsent(String key, String value) {
+        return _redisTemplate.opsForValue().setIfAbsent(key, value);
+    }
+
+    /**
+     * 普通缓存放入并设置时间
+     *
+     * @param key   键
+     * @param value 值
+     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
+     * @return true成功 false 失败
+     */
+    public boolean set(String key, Object value, long time) {
+        try {
+            if (time > 0) {
+                _redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
+            } else {
+                set(key, value);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 递增
+     *
+     * @param key   键
+     * @param delta 要增加几(大于0)
+     * @return
+     */
+    public Long increment(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递增因子必须大于0");
+        }
+        return _redisTemplate.opsForValue().increment(key, delta);
+    }
+
+    /**
+     * 递减
+     *
+     * @param key   键
+     * @param delta 要减少几(小于0)
+     * @return
+     */
+    public Long decrement(String key, long delta) {
+        if (delta < 0) {
+            throw new RuntimeException("递减因子必须大于0");
+        }
+        return _redisTemplate.opsForValue().decrement(key, delta);
+    }
+
+    // ================================Map=================================
+
+    /**
+     * HashGet
+     *
+     * @param key  键 不能为null
+     * @param item 项 不能为null
+     * @return 值
+     */
+    public Object hget(String key, String item) {
+        return _redisTemplate.opsForHash().get(key, item);
+    }
+
+    /**
+     * 获取hashKey对应的所有键值
+     *
+     * @param key 键
+     * @return 对应的多个键值
+     */
+    public Map<Object, Object> hmget(String key) {
+        return _redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * 获取hashKey对应的所有键值
+     *
+     * @param key 键
+     * @return 对应的多个键值
+     */
+    public <T> Map<String, T> hmget(String key, Class<T> pValClass) {
+        Map<Object, Object> rtn = _redisTemplate.opsForHash().entries(key);
+        Map<String, T> result = MapUtil.newHashMap();
+        for (Map.Entry<Object, Object> data : rtn.entrySet()) {
+            String subKey = data.getKey().toString();
+            T value = JSONUtil.toBean(JSONUtil.toJsonStr(data.getValue()), pValClass);
+            result.put(subKey, value);
+        }
+        return result;
+    }
+
+
+    /**
+     * 使用hget获取Redis对象
+     *
+     * @param key 键
+     * @return 返回对象
+     */
+    public <T> T hmgetObj(String key) {
+        Map<String, Object> mpData = _hashOperations.entries(key);
+        if (mpData.size() == 0) {
+            return null;
+        }
+        return (T) _hashMapper.fromHash(mpData);
+    }
+
+    /**
+     * HashSet
+     *
+     * @param key 键
+     * @param map 对应多个键值
+     * @return true 成功 false 失败
+     */
+    public boolean hmset(String key, Map<String, Object> map) {
+        try {
+            _redisTemplate.opsForHash().putAll(key, map);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 使用hset对指定键放入对象的所有值
+     *
+     * @param key     键
+     * @param v_obj   对象
+     * @param <T>对象类型
+     * @return 是否成功
+     */
+    public <T> boolean hmsetObject(String key, T v_obj) {
+        try {
+            Map<String, Object> mappedHash = _hashMapper.toHash(v_obj);
+            _hashOperations.putAll(key, mappedHash);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * HashSet 并设置时间
+     *
+     * @param key  键
+     * @param map  对应多个键值
+     * @param time 时间(秒)
+     * @return true成功 false失败
+     */
+    public boolean hmset(String key, Map<String, Object> map, long time) {
+        try {
+            _redisTemplate.opsForHash().putAll(key, map);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 使用hset对指定键放入对象的所有值,并设置过期时间
+     *
+     * @param key     键
+     * @param v_obj   对象
+     * @param <T>对象类型
+     * @return 是否成功
+     */
+    public <T> boolean hmsetObject(String key, T v_obj, long time) {
+        try {
+            Map<String, Object> mappedHash = _hashMapper.toHash(v_obj);
+            _hashOperations.putAll(key, mappedHash);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key   键
+     * @param item  项
+     * @param value 值
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key, String item, Object value) {
+        try {
+            _redisTemplate.opsForHash().put(key, item, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 向一张hash表中放入数据,如果不存在将创建
+     *
+     * @param key   键
+     * @param item  项
+     * @param value 值
+     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
+     * @return true 成功 false失败
+     */
+    public boolean hset(String key, String item, Object value, long time) {
+        try {
+            _redisTemplate.opsForHash().put(key, item, value);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 删除hash表中的值
+     *
+     * @param key  键 不能为null
+     * @param item 项 可以使多个 不能为null
+     */
+    public void hdel(String key, Object... item) {
+        _redisTemplate.opsForHash().delete(key, item);
+    }
+
+    /**
+     * 判断hash表中是否有该项的值
+     *
+     * @param key  键 不能为null
+     * @param item 项 不能为null
+     * @return true 存在 false不存在
+     */
+    public boolean hHasKey(String key, String item) {
+        return _redisTemplate.opsForHash().hasKey(key, item);
+    }
+
+    /**
+     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
+     *
+     * @param key  键
+     * @param item 项
+     * @param by   要增加几(大于0)
+     * @return
+     */
+    public double hincr(String key, String item, double by) {
+        return _redisTemplate.opsForHash().increment(key, item, by);
+    }
+
+    /**
+     * hash递减
+     *
+     * @param key  键
+     * @param item 项
+     * @param by   要减少记(小于0)
+     * @return
+     */
+    public double hdecr(String key, String item, double by) {
+        return _redisTemplate.opsForHash().increment(key, item, -by);
+    }
+    // ============================set=============================
+
+    /**
+     * 根据key获取Set中的所有值
+     *
+     * @param key 键
+     * @return
+     */
+    public Set<Object> sGet(String key) {
+        try {
+            return _redisTemplate.opsForSet().members(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 根据value从一个set中查询,是否存在
+     *
+     * @param key   键
+     * @param value 值
+     * @return true 存在 false不存在
+     */
+    public Boolean sHasKey(String key, Object value) {
+        try {
+            return _redisTemplate.opsForSet().isMember(key, value);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 将数据放入set缓存
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public Long sSet(String key, Object... values) {
+        try {
+            return _redisTemplate.opsForSet().add(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0L;
+        }
+    }
+
+    /**
+     * 将set数据放入缓存
+     *
+     * @param key    键
+     * @param time   时间(秒)
+     * @param values 值 可以是多个
+     * @return 成功个数
+     */
+    public Long sSetAndTime(String key, long time, Object... values) {
+        try {
+            Long count = _redisTemplate.opsForSet().add(key, values);
+            if (time > 0) {
+                expire(key, time);
+            }
+            return count;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0L;
+        }
+    }
+
+    /**
+     * 获取set缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+    public Long sGetSetSize(String key) {
+        try {
+            return _redisTemplate.opsForSet().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0L;
+        }
+    }
+
+    /**
+     * 移除值为value的
+     *
+     * @param key    键
+     * @param values 值 可以是多个
+     * @return 移除的个数
+     */
+    public Long setRemove(String key, Object... values) {
+        try {
+            return _redisTemplate.opsForSet().remove(key, values);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0L;
+        }
+    }
+    // ===============================list=================================
+
+    /**
+     * 获取list缓存的内容
+     *
+     * @param key   键
+     * @param start 开始
+     * @param end   结束 0 到 -1代表所有值
+     * @return
+     */
+    public List<Object> lGet(String key, long start, long end) {
+        try {
+            return _redisTemplate.opsForList().range(key, start, end);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 获取list缓存的长度
+     *
+     * @param key 键
+     * @return
+     */
+    public Long getListSize(String key) {
+        try {
+            return _redisTemplate.opsForList().size(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return 0L;
+        }
+    }
+
+    /**
+     * 通过索引 获取list中的值
+     *
+     * @param key   键
+     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
+     * @return
+     */
+    public Object listGet(String key, long index) {
+        try {
+            return _redisTemplate.opsForList().index(key, index);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 根据索引修改list中的某条数据
+     *
+     * @param key   键
+     * @param index 索引
+     * @param value 值
+     * @return
+     */
+    public boolean listSet(String key, long index, Object value) {
+        try {
+            _redisTemplate.opsForList().set(key, index, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 把值放入队尾
+     *
+     * @param key   键
+     * @param value 值
+     * @return
+     */
+    public boolean rPush(String key, Object value) {
+        try {
+            _redisTemplate.opsForList().rightPush(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 把值放入队首
+     *
+     * @param key   键
+     * @param value 值
+     * @return
+     */
+    public boolean lPush(String key, Object value) {
+        try {
+            _redisTemplate.opsForList().leftPush(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 批量插入队尾
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public boolean rPushAll(String key, List<Object> value) {
+        try {
+            _redisTemplate.opsForList().rightPushAll(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 批量插入队首
+     *
+     * @param key
+     * @param value
+     * @return
+     */
+    public boolean lPushAll(String key, List<Object> value) {
+        try {
+            _redisTemplate.opsForList().leftPushAll(key, value);
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        }
+    }
+
+    /**
+     * 从队首推出一个元素
+     *
+     * @param key 键
+     * @return 队首元素
+     */
+    public Object lPop(String key) {
+        try {
+            return _redisTemplate.opsForList().leftPop(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /**
+     * 从队尾推出一个元素
+     *
+     * @param key 键
+     * @return 队首元素
+     */
+    public Object rPop(String key) {
+        try {
+            return _redisTemplate.opsForList().rightPop(key);
+        } catch (Exception e) {
+            e.printStackTrace();
+            return null;
+        }
+    }
+
+    /*********************************pipeline*****************/
+
+    public <T> List<Object> executePipelined(RedisCallback<T> pFnCallBack) {
+        return _redisTemplate.executePipelined(pFnCallBack, _redisTemplate.getValueSerializer());
+    }
+
+    public List<String> keys(String pPattern) {
+        return new ArrayList<>(Objects.requireNonNull(_redisTemplate.keys(pPattern)));
+    }
+
+    public void batchRemove(List<String> pKeyList) {
+        new RedisCallback<Integer>() {
+            @Override
+            public Integer doInRedis(RedisConnection connection) throws DataAccessException {
+                connection.openPipeline();
+                for (String key : pKeyList) {
+                    connection.expire(key.getBytes(), 1);
+                }
+                return 0;
+            }
+        };
+    }
+}
+

+ 43 - 0
src/main/java/com/smppw/analysis/infrastructure/config/RedisConfig.java

@@ -0,0 +1,43 @@
+package com.smppw.analysis.infrastructure.config;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+@Configuration
+public class RedisConfig {
+    @Bean
+    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
+        RedisTemplate<String, Object> template = new RedisTemplate<>();
+        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
+        ObjectMapper om = new ObjectMapper();
+        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
+        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(om, Object.class);
+        template.setConnectionFactory(factory);
+        //key序列化方式
+        template.setKeySerializer(redisSerializer);
+        //value序列化
+        template.setValueSerializer(jackson2JsonRedisSerializer);
+        //value hashmap序列化
+        template.setHashValueSerializer(jackson2JsonRedisSerializer);
+        // value hashkey序列化
+        template.setHashKeySerializer(redisSerializer);
+        return template;
+    }
+
+    @Bean
+    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory) {
+        StringRedisTemplate stringRedisTemplate = new StringRedisTemplate();
+        stringRedisTemplate.setConnectionFactory(factory);
+        return stringRedisTemplate;
+    }
+}

+ 0 - 48
src/main/java/com/smppw/analysis/infrastructure/utils/DateValueUtil.java

@@ -1,48 +0,0 @@
-package com.smppw.analysis.infrastructure.utils;
-
-import com.smppw.common.pojo.dto.DateValue;
-import com.smppw.common.pojo.dto.NavDto;
-import com.smppw.common.pojo.enums.NavType;
-
-import java.math.BigDecimal;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-public class DateValueUtil {
-
-    public static List<DateValue> convertNavList(List<NavDto> navDtoList, NavType navType) {
-        List<DateValue> dateValueList = new ArrayList<>();
-        for (NavDto navDto : navDtoList) {
-            DateValue dateValue = new DateValue();
-            dateValue.setDate(navDto.getPriceDate());
-            if (NavType.WithdrawalNav == navType) {
-                dateValue.setValue(navDto.getCumulativeNavWithdrawal() != null ? navDto.getCumulativeNavWithdrawal().doubleValue() : null);
-            } else if (NavType.OriginalNav == navType) {
-                dateValue.setValue(navDto.getOriginalNav() != null ? navDto.getOriginalNav().doubleValue() : null);
-            } else if (NavType.All == navType) {
-                dateValue.setValue(navDto.getOriginalNav() != null ? navDto.getOriginalNav().doubleValue() : null);
-                dateValue.setOriginalNav(navDto.getOriginalNav() != null ? navDto.getOriginalNav() : null);
-                dateValue.setCumulativeNav(navDto.getCumulativeNav() != null ? navDto.getCumulativeNav() : null);
-                dateValue.setCumulativeNavWithdrawal(navDto.getCumulativeNavWithdrawal() != null ? navDto.getCumulativeNavWithdrawal() : null);
-            } else {
-                dateValue.setValue(navDto.getCumulativeNav() != null ? navDto.getCumulativeNav().doubleValue() : null);
-            }
-            dateValueList.add(dateValue);
-        }
-        return dateValueList;
-    }
-    public static List<Map<String, Object>> convertDecimalMapToList(Map<String, BigDecimal> originalMap) {
-        List<Map<String, Object>> resultList = new ArrayList<>();
-        for (Map.Entry<String, BigDecimal> entry : originalMap.entrySet()) {
-            String date = entry.getKey();
-            Map<String, Object> convertedMap = new HashMap<>();
-            convertedMap.put("date", date);
-            convertedMap.put("value", entry.getValue());
-            resultList.add(convertedMap);
-        }
-        return resultList;
-    }
-
-}