SchedulingCache.java 9.57 KB
package com.ruoyi.common.cache;

import com.ruoyi.common.SchedulerProperty;
import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.pojo.response.ResponseSchedulingDto;
import com.ruoyi.utils.ConstDateUtil;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;

import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.ruoyi.common.redispre.GlobalRedisPreName.DRIVER_SCHEDULING_PRE;

/**
 * 排班缓存
 *
 * @author 20412
 */
@Component
public class SchedulingCache {

    private static final Logger log = LoggerFactory.getLogger(SchedulingCache.class);
    @Autowired
    private RedisCache redisCache;
    @Autowired
    private RedisTemplate redisTemplate;


    /**
     * 实时更新排班
     */
    private static final ConcurrentHashMap<String, Map<String, List<ResponseSchedulingDto>>> CONCURRENT_HASH_MAP = new ConcurrentHashMap<>();


    public SchedulingCache(SchedulerProperty property,RedisCache redisCache) {
        log.info("项目启动加载中获取实时班次并存入缓存-----");
        this.redisCache = redisCache;
        schedulingInit(property);
    }


    /**
     * 初始化排班数据 并存入缓存
     */
    private void schedulingInit(SchedulerProperty property) {
        String formatNowDate = ConstDateUtil.formatDate(new Date());
        String url = getUrl(formatNowDate, property);
        log.info("初始化排班数据:{}", formatNowDate);
        saveSchedulingToCache(url, formatNowDate);
        String formatYesterdayDate = ConstDateUtil.formatDate(ConstDateUtil.getTheSpecifiedNumberOfDaysOfTime(-1));
        log.info("初始化排班数据:{}", formatYesterdayDate);
        url = getUrlOld(formatYesterdayDate, property);
        saveSchedulingToCache(url, formatYesterdayDate);
    }

    public String getUrl(String formatNowDate, SchedulerProperty property) {
        String url = null;
        long timestamp = System.currentTimeMillis();
//        String formatDate = ConstDateUtil.formatDate(ConstDateUtil.getTheSpecifiedNumberOfDaysOfTime(-1));
        // 获取排班请求
        String key = "Scheduling:timeStr:" + formatNowDate;
        try {
            long timestampValue = timestamp;
            if (!redisCache.hasKey(key)) {
                redisCache.setCacheObject(key, "1", 30, TimeUnit.HOURS);
                timestampValue = 0;
            }
            url = String.format(property.getGetSchedulingInfoUrl(), "77", formatNowDate, timestampValue, timestamp, property.getNonce(), property.getPassword(), getSHA1(getStringStringMap(String.valueOf(timestamp), property)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return url;
    }

    public String getUrlOld(String formatNowDate, SchedulerProperty property) {
        String url = null;
        long timestamp = System.currentTimeMillis();
//        String formatDate = ConstDateUtil.formatDate(ConstDateUtil.getTheSpecifiedNumberOfDaysOfTime(-1));
        // 获取排班请求
        try {
            url = String.format(property.getGetSchedulingInfo(), "77", formatNowDate, timestamp, property.getNonce(), property.getPassword(), getSHA1(getStringStringMap(String.valueOf(timestamp), property)));
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return url;
    }

    /**
     * 获取签名
     *
     * @param map
     * @return
     * @throws Exception
     */
    private String getSHA1(Map<String, String> map) throws Exception {
        try {
            String[] array = new String[map.size()];
            map.values().toArray(array);
            StringBuffer sb = new StringBuffer();
            // 字符串排序
            Arrays.sort(array);
            for (int i = 0; i < array.length; i++) {
                sb.append(array[i]);
            }
            String str = sb.toString();
            // SHA1签名生成
            MessageDigest md = MessageDigest.getInstance("SHA-1");
            md.update(str.getBytes());
            byte[] digest = md.digest();
            StringBuffer hexstr = new StringBuffer();
            String shaHex = "";
            for (int i = 0; i < digest.length; i++) {
                shaHex = Integer.toHexString(digest[i] & 0xFF);
                if (shaHex.length() < 2) {
                    hexstr.append(0);
                }
                hexstr.append(shaHex);
            }
            return hexstr.toString();
        } catch (Exception e) {
            throw e;
        }


    }


    private Map<String, List<ResponseSchedulingDto>> saveSchedulingToCache(String getSchedulingInfoUrl, String dateKey) {
        log.info("开始拉取排班:{}", dateKey);
        List<ResponseSchedulingDto> originSchedulingList = new RestTemplate().exchange(
                getSchedulingInfoUrl,
                HttpMethod.GET,
                null,
                new ParameterizedTypeReference<List<ResponseSchedulingDto>>() {
                }).getBody();

        Map<String, List<ResponseSchedulingDto>> driverSchedulingMap = new HashMap<>(200);
        // 按照员工工号来获取排班信息
        originSchedulingList = originSchedulingList.stream()
                .map(subItem -> {
                    subItem.setJobCode(subItem.getJsy().split("/")[0]);
                    return subItem;
                }).collect(Collectors.toList());
        // 以员工号为key存入排班集合
        originSchedulingList.stream().forEach(item -> {
            // 员工号为key
            String jobCode = item.getJsy().split("/")[0];
            String salePersonJobCode = item.getSpy().split("/").length > 0 ? item.getSpy().split("/")[0] : null;
            item.setJobCode(jobCode);
            splitSaveScheduling(driverSchedulingMap, jobCode, item);
            splitSaveScheduling(driverSchedulingMap, salePersonJobCode, item);
        });

        // 排序
        List<String> keys = new ArrayList<>(driverSchedulingMap.keySet());
        for (String key : keys) {
            List<ResponseSchedulingDto> schedulingList = driverSchedulingMap.get(key);
            schedulingList.sort(Comparator.comparing(ResponseSchedulingDto::getFcsjT));
        }
        // 存入数据库
//        DRIVER_SERVICE.saveDriverScheduling(originSchedulingList);
        // 存入redis
        setCacheScheduling(DRIVER_SCHEDULING_PRE + dateKey, driverSchedulingMap);
//        REDIS_CACHE.setCacheMap(DRIVER_SCHEDULING_PRE + dateKey, driverSchedulingMap, 2, TimeUnit.DAYS);
        log.info("拉取排班完毕:{}", dateKey);
        return driverSchedulingMap;
    }

    public List<ResponseSchedulingDto> requestScheduling(String getSchedulingInfoUrl) {
        List<ResponseSchedulingDto> originSchedulingList = null;
        int index = 0;
        int size = 0;
        while (size == 0) {
            originSchedulingList = new RestTemplate().exchange(
                    getSchedulingInfoUrl, HttpMethod.GET, null, new ParameterizedTypeReference<List<ResponseSchedulingDto>>() {
                    }).getBody();
            size = CollectionUtils.size(originSchedulingList);
            index++;
            if (index > 10 || size > 0) {
                break;
            }
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        return originSchedulingList;
    }

    private void splitSaveScheduling(Map<String, List<ResponseSchedulingDto>> driverSchedulingMap, String jobCode, ResponseSchedulingDto item) {
        if (!Objects.isNull(jobCode))
            if (Objects.isNull(driverSchedulingMap.get(jobCode))) {
                List<ResponseSchedulingDto> oneDriverScheduling = new ArrayList<>();
                oneDriverScheduling.add(item);
                driverSchedulingMap.put(jobCode, oneDriverScheduling);
            } else {
                driverSchedulingMap.get(jobCode).add(item);
            }
    }

    private Map<String, String> getStringStringMap(String timestamp, SchedulerProperty property) {
        Map<String, String> configMap = new HashMap<>(5);
        configMap.put("timestamp", String.valueOf(timestamp));
        configMap.put("nonce", property.getNonce());
        configMap.put("password", property.getPassword());
        return configMap;
    }

    public void setCacheScheduling(String key, Map<String, List<ResponseSchedulingDto>> mapValue) {
        CONCURRENT_HASH_MAP.put(key, mapValue);
    }

    public void removeCacheSchedulingByKey(String key) {
        CONCURRENT_HASH_MAP.remove(key);
    }

    public List<String> getKeys() {
        return new ArrayList<>(CONCURRENT_HASH_MAP.keySet());
    }

    public Integer size() {
        return CONCURRENT_HASH_MAP.size();
    }

    public List<ResponseSchedulingDto> getCacheSchedulingMapValueByHKey(String key, String HKey) {
        Map<String, List<ResponseSchedulingDto>> map = CONCURRENT_HASH_MAP.get(key);
        if (Objects.isNull(map)) {
            return null;
        }
        List<ResponseSchedulingDto> list = map.get(HKey);

        return Objects.isNull(list) ? null : list;
    }

    public List<String> getHKeysByKey(String key) {
        return new ArrayList<>(CONCURRENT_HASH_MAP.get(key).keySet());
    }

}