Commit d772bb98 by Ren Ping

feat:路网更新为redis缓存

1 parent 810f3686
...@@ -19,6 +19,7 @@ package com.dituhui.pea.dispatch; ...@@ -19,6 +19,7 @@ package com.dituhui.pea.dispatch;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients; import org.springframework.cloud.openfeign.EnableFeignClients;
import org.springframework.context.annotation.Import;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
/** /**
...@@ -27,6 +28,7 @@ import org.springframework.scheduling.annotation.EnableScheduling; ...@@ -27,6 +28,7 @@ import org.springframework.scheduling.annotation.EnableScheduling;
@SpringBootApplication @SpringBootApplication
@EnableScheduling @EnableScheduling
@EnableFeignClients(basePackages = {"com.dituhui.pea.user"}) @EnableFeignClients(basePackages = {"com.dituhui.pea.user"})
@Import(cn.hutool.extra.spring.SpringUtil.class)
public class DispatchServiceApplication { public class DispatchServiceApplication {
public static void main(String[] args) { public static void main(String[] args) {
......
package com.dituhui.pea.dispatch.common; package com.dituhui.pea.dispatch.common.redis;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate; import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer;
@Configuration @Configuration
...@@ -16,10 +21,27 @@ public class RedisConfig { ...@@ -16,10 +21,27 @@ public class RedisConfig {
// objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), // objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(),
// ObjectMapper.DefaultTyping.EVERYTHING, JsonTypeInfo.As.PROPERTY); // ObjectMapper.DefaultTyping.EVERYTHING, JsonTypeInfo.As.PROPERTY);
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)
Jackson2JsonRedisSerializer jacksonSerial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
// 指定要序列化的域,field, get和set,以及修饰符范围,ANY是都有包括private和public
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
// jsonToBean时,json中有的字段,bean中没有 无法匹配时,忽略此字段,不抛出异常(默认是抛出异常的)
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
jacksonSerial.setObjectMapper(objectMapper);
RedisTemplate<String, String> redisTemplate = new RedisTemplate<>(); RedisTemplate<String, String> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(connectionFactory); redisTemplate.setConnectionFactory(connectionFactory);
redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new StringRedisSerializer()); redisTemplate.setValueSerializer(jacksonSerial);
// 设置hash key 和 value 序列化模式
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jacksonSerial);
return redisTemplate; return redisTemplate;
} }
......
package com.dituhui.pea.dispatch.common.redis;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
/**
* @Description: TODO redis 工具类
* @Author: RenPing
* @Date: 2022/7/25 10:27
* @Version: 1.0
*/
@Slf4j
@Component
public class RedisUtil {
private static RedisTemplate<String, Object> redisTemplate;
@PostConstruct
public void init() {
redisTemplate = SpringUtil.getBean("redisTemplate");
}
// ============================ Common ============================
/**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public static boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public static long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
}
/**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public static boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
public static void del(String... key) {
if (ObjectUtil.isNotEmpty(key)) {
redisTemplate.delete(Arrays.asList(key));
}
}
/**
* 模糊查询并删除key,如:cache:user:*
*
* @param regex
*/
public static void deleteByKeys(String regex) {
Set<String> keys = redisTemplate.keys(regex);
if (ObjectUtil.isNotEmpty(keys)) {
redisTemplate.delete(keys);
}
}
// ============================ String ============================
/**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public static Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
}
/**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public static boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public static 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) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public static long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
}
/**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public static long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
}
// ============================ Map ============================
/**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public static Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
}
/**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public static Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
}
/**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public static boolean hmset(String key, Map<Object, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public static boolean hmset(String key, Map<Object, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public static boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public static 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) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public static void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
}
/**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public static boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
}
/**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public static 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 static double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
}
// ============================ set ============================
/**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public static Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public static boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public static long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public static 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) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public static long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public static long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
// ============================ list ============================
/**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public static List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public static long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
/**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public static Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
log.error(e.getMessage(), e);
return null;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public static boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public static boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @return
*/
public static boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public static boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* 507
* @param value 值
* @return
*/
public static boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
log.error(e.getMessage(), e);
return false;
}
}
/**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public static long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
log.error(e.getMessage(), e);
return 0;
}
}
}
package com.dituhui.pea.dispatch.common; package com.dituhui.pea.dispatch.common.redis;
import org.redisson.Redisson; import org.redisson.Redisson;
import org.redisson.api.RedissonClient; import org.redisson.api.RedissonClient;
......
package com.dituhui.pea.dispatch.common; package com.dituhui.pea.dispatch.common.redis;
import cn.hutool.extra.spring.SpringUtil; import cn.hutool.extra.spring.SpringUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
......
package com.dituhui.pea.dispatch.constraint;
public class RedisKeyConstant {
public static final String LOCATION_DISTANCE_KEY = "location:%s:distance:%s";
public static final String LOCATION_DISTANCE_TIME_KEY = "location:%s:distanceTime:%s";
}
package com.dituhui.pea.dispatch.quartz.dispatch; package com.dituhui.pea.dispatch.quartz.dispatch;
import com.dituhui.pea.dispatch.common.RedissonUtil;
import com.dituhui.pea.dispatch.service.SchedulerService; import com.dituhui.pea.dispatch.service.SchedulerService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.quartz.DisallowConcurrentExecution; import org.quartz.DisallowConcurrentExecution;
......
...@@ -40,9 +40,9 @@ public class BatchScheduler { ...@@ -40,9 +40,9 @@ public class BatchScheduler {
@Autowired @Autowired
ExtractService extractService; ExtractService extractService;
@Autowired @Autowired
OrgTeamDao orgTeamDao; OrgTeamDao orgTeamDao;
private DefaultSolverFactory<DispatchSolution> solverFactory; private DefaultSolverFactory<DispatchSolution> solverFactory;
private Solver<DispatchSolution> solver; private Solver<DispatchSolution> solver;
...@@ -52,22 +52,22 @@ public class BatchScheduler { ...@@ -52,22 +52,22 @@ public class BatchScheduler {
solver = solverFactory.buildSolver(); solver = solverFactory.buildSolver();
} }
/* /*
* 异步执行任务开始 * 异步执行任务开始
*/ */
//@Scheduled(cron = "${dispatch.cron.expr}") //@Scheduled(cron = "${dispatch.cron.expr}")
public void dispatchRun2() { public void dispatchRun2() {
String groupId = "gsuzhou"; String groupId = "gsuzhou";
log.info("dispatchRun group:{}", groupId); log.info("dispatchRun group:{}", groupId);
// TODO 分布式任务,循环大区/分部/分站/小队 // TODO 分布式任务,循环大区/分部/分站/小队
// 循环分站/网点下面的小队 // 循环分站/网点下面的小队
List<OrgTeamEntity> teams = orgTeamDao.findByGroupId(groupId); List<OrgTeamEntity> teams = orgTeamDao.findByGroupId(groupId);
for (OrgTeamEntity team : teams) { for (OrgTeamEntity team : teams) {
String teamId = team.getTeamId(); String teamId = team.getTeamId();
for (int i = 1; i <= nextDaysLimit; i++) { for (int i = 1; i <= nextDaysLimit; i++) {
String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE); String currDay = LocalDate.now().plusDays(i).format(DateTimeFormatter.ISO_LOCAL_DATE);
log.info("dispatchRun begin----- teamId:{}, day:{}", teamId, currDay); log.info("dispatchRun begin----- teamId:{}, day:{}", teamId, currDay);
String batchNo = batchService.buildBatchData2(teamId, currDay, false); String batchNo = batchService.buildBatchData2(teamId, currDay, false);
UUID problemId = solveService.generateProblemId(teamId, batchNo); UUID problemId = solveService.generateProblemId(teamId, batchNo);
...@@ -88,19 +88,19 @@ public class BatchScheduler { ...@@ -88,19 +88,19 @@ public class BatchScheduler {
log.info("dispatchRun done ------ teamId:{}, day:{}", teamId, currDay); log.info("dispatchRun done ------ teamId:{}, day:{}", teamId, currDay);
JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(DispatchSolution.class); JacksonSolutionFileIO<DispatchSolution> exporter = new JacksonSolutionFileIO<DispatchSolution>(DispatchSolution.class);
exporter.write(solution, new File(String.format("dispatchSolution_%s_%s.json",teamId, currDay))); exporter.write(solution, new File(String.format("dispatchSolution_%s_%s.json", teamId, currDay)));
} }
} }
log.info("dispatchRun group:{} done", groupId);
}
log.info("dispatchRun group:{} done", groupId);
}
/* /*
* 异步执行任务开始 * 异步执行任务开始
* */ * */
//@Scheduled(cron = "${dispatch.cron.expr}") //@Scheduled(cron = "${dispatch.cron.expr}")
public void dispatchRun() { public void dispatchRun() {
String groupId = "gsuzhou"; String groupId = "gsuzhou";
log.info("dispatchRun group:{}", groupId); log.info("dispatchRun group:{}", groupId);
try { try {
for (int i = 0; i <= nextDaysLimit; i++) { for (int i = 0; i <= nextDaysLimit; i++) {
...@@ -155,7 +155,7 @@ public class BatchScheduler { ...@@ -155,7 +155,7 @@ public class BatchScheduler {
// Set the output file. // Set the output file.
exporter.write(solution, new File(String.format("dispatchSolution_%s_%s.json",groupId, currDay))); exporter.write(solution, new File(String.format("dispatchSolution_%s_%s.json", groupId, currDay)));
Thread.sleep(1000 * 5); Thread.sleep(1000 * 5);
......
...@@ -3,9 +3,12 @@ package com.dituhui.pea.dispatch.service.impl; ...@@ -3,9 +3,12 @@ package com.dituhui.pea.dispatch.service.impl;
import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.nacos.common.utils.CollectionUtils; import com.alibaba.nacos.common.utils.CollectionUtils;
import com.dituhui.pea.dispatch.dao.*; import com.dituhui.pea.dispatch.dao.*;
import com.dituhui.pea.dispatch.entity.*; import com.dituhui.pea.dispatch.entity.*;
import com.dituhui.pea.dispatch.pojo.Customer;
import com.dituhui.pea.dispatch.pojo.DispatchSolution;
import com.dituhui.pea.dispatch.service.ExtractService; import com.dituhui.pea.dispatch.service.ExtractService;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
...@@ -295,7 +298,13 @@ public class ExtractServiceImpl implements ExtractService { ...@@ -295,7 +298,13 @@ public class ExtractServiceImpl implements ExtractService {
orderInfo.setArriveElapsed(0); orderInfo.setArriveElapsed(0);
orderInfo.setArriveDistance(0); orderInfo.setArriveDistance(0);
orderInfo.setAppointmentStatus("INIT"); orderInfo.setAppointmentStatus("INIT");
orderInfo.setDispatcher("AUTO_BATCH"); if (cutOff) {
orderInfo.setAppointmentMethod("MANUAL");
orderInfo.setDispatcher("MANUAL");
log.info("算法结果更新到工单为人工, teamId:{}, batchNo:{}, orderId:{}", teamId, batchNo, orderId);
} else {
orderInfo.setDispatcher("AUTO_BATCH");
}
orderInfo.setUpdateTime(LocalDateTime.now()); orderInfo.setUpdateTime(LocalDateTime.now());
orderInfoRepo.save(orderInfo); orderInfoRepo.save(orderInfo);
......
...@@ -3,7 +3,6 @@ package com.dituhui.pea.dispatch.service.impl; ...@@ -3,7 +3,6 @@ package com.dituhui.pea.dispatch.service.impl;
import cn.hutool.core.date.DateUtil; import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import com.dituhui.pea.dispatch.common.RedissonUtil;
import com.dituhui.pea.dispatch.dao.DispatchBatchRepository; import com.dituhui.pea.dispatch.dao.DispatchBatchRepository;
import com.dituhui.pea.dispatch.dao.OrgGroupRepository; import com.dituhui.pea.dispatch.dao.OrgGroupRepository;
import com.dituhui.pea.dispatch.dao.OrgTeamDao; import com.dituhui.pea.dispatch.dao.OrgTeamDao;
...@@ -11,7 +10,6 @@ import com.dituhui.pea.dispatch.entity.DispatchBatch; ...@@ -11,7 +10,6 @@ import com.dituhui.pea.dispatch.entity.DispatchBatch;
import com.dituhui.pea.dispatch.entity.OrgGroup; import com.dituhui.pea.dispatch.entity.OrgGroup;
import com.dituhui.pea.dispatch.entity.OrgTeamEntity; import com.dituhui.pea.dispatch.entity.OrgTeamEntity;
import com.dituhui.pea.dispatch.pojo.DispatchSolution; import com.dituhui.pea.dispatch.pojo.DispatchSolution;
import com.dituhui.pea.dispatch.quartz.dispatch.AutoDispatchJob;
import com.dituhui.pea.dispatch.service.BatchService; import com.dituhui.pea.dispatch.service.BatchService;
import com.dituhui.pea.dispatch.service.ExtractService; import com.dituhui.pea.dispatch.service.ExtractService;
import com.dituhui.pea.dispatch.service.SchedulerService; import com.dituhui.pea.dispatch.service.SchedulerService;
......
...@@ -2,6 +2,7 @@ package com.dituhui.pea.dispatch.utils; ...@@ -2,6 +2,7 @@ package com.dituhui.pea.dispatch.utils;
import java.io.BufferedReader; import java.io.BufferedReader;
import java.io.InputStreamReader; import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.net.URLConnection; import java.net.URLConnection;
...@@ -10,6 +11,8 @@ import java.util.HashMap; ...@@ -10,6 +11,8 @@ import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import cn.hutool.core.util.StrUtil;
import com.dituhui.pea.dispatch.common.redis.RedisUtil;
import org.springframework.stereotype.Component; import org.springframework.stereotype.Component;
import com.dituhui.pea.dispatch.pojo.Location; import com.dituhui.pea.dispatch.pojo.Location;
...@@ -23,192 +26,214 @@ import lombok.extern.slf4j.Slf4j; ...@@ -23,192 +26,214 @@ import lombok.extern.slf4j.Slf4j;
* 路网组件<br> * 路网组件<br>
* TODO 需要做成分布式缓存模式,这里会造成内存问题<br> * TODO 需要做成分布式缓存模式,这里会造成内存问题<br>
* TODO 调用方式需要改成批量调用方式 * TODO 调用方式需要改成批量调用方式
*
* @author gpzhang
* *
* @author gpzhang
*/ */
@Component @Component
@Slf4j @Slf4j
public class RoadDistanceUtils { public class RoadDistanceUtils {
public static String URL = "https://api.map.baidu.com/routematrix/v2/"; public static String URL = "https://api.map.baidu.com/routematrix/v2/";
public static String AK = "doR30pE7R0I7ivGLwMpkpsTT4bos9Akg"; public static String AK = "doR30pE7R0I7ivGLwMpkpsTT4bos9Akg";
/** /**
* 格式 x1,y1;x2,y2 * 格式 x1,y1;x2,y2
*/ */
private static Map<String, Distance> distanceCache = Maps.newHashMap(); //private static Map<String, Distance> distanceCache = Maps.newHashMap();
private static Gson gson = new Gson(); private static Gson gson = new Gson();
/** /**
* 获取路网距离和时间<br> * 获取路网距离和时间<br>
* *
* @param from * @param from
* @param to * @param to
* @param vehicleType 不能为空 * @param vehicleType 不能为空
* @return * @return
*/ */
public Distance getDistance2(Location from, Location to, int vehicleType) { public Distance getDistance2(Location from, Location to, int vehicleType) {
try { try {
String key = from.getLongitude() + "," + from.getLatitude() + ";" + to.getLongitude() + "," String key = getLocationKey(from, to, vehicleType);
+ to.getLatitude() + "|" + vehicleType; //Distance distance = distanceCache.get(key);
Distance distance = distanceCache.get(key); Distance distance = (Distance) RedisUtil.get(key);
if (null == distance) { if (null == distance) {
distance = getDistance(from.getLatitude() + "," + from.getLongitude(), distance = getDistance(from.getLatitude() + "," + from.getLongitude(),
to.getLatitude() + "," + to.getLongitude(), vehicleType); to.getLatitude() + "," + to.getLongitude(), vehicleType);
log.info(key + " " + distance); log.info(key + " " + distance);
if (null == distance) { if (null == distance) {
Distance dis = new Distance(); Distance dis = new Distance();
return dis; return dis;
} else { } else {
distanceCache.put(key, distance); //distanceCache.put(key, distance);
} RedisUtil.set(key, distance);
return distance; }
} else { return distance;
log.info(key + " from cache " + distance); } else {
return distance; log.info(key + " from cache " + distance);
} return distance;
} catch (Exception e) { }
Distance dis = new Distance(); } catch (Exception e) {
return dis; Distance dis = new Distance();
} return dis;
} }
}
/**
* 获取路网距离和时间<br> /**
* TODO 需要做成分布式缓存模式,这里会造成内存问题<br> * 获取路网距离和时间<br>
* TODO 调用方式需要改成批量调用方式 * TODO 需要做成分布式缓存模式,这里会造成内存问题<br>
* * TODO 调用方式需要改成批量调用方式
* @param from *
* @param to * @param from
* @param vehicleType 不能为空 * @param to
* @return * @param vehicleType 不能为空
*/ * @return
public static Distance getDistance(Location from, Location to, int vehicleType) { */
try { public static Distance getDistance(Location from, Location to, int vehicleType) {
String key = from.getLongitude() + "," + from.getLatitude() + ";" + to.getLongitude() + "," try {
+ to.getLatitude() + "|" + vehicleType; String key = getLocationKey(from, to, vehicleType);
Distance distance = distanceCache.get(key); //Distance distance = distanceCache.get(key);
if (null == distance) { Distance distance = (Distance) RedisUtil.get(key);
distance = getDistance(from.getLatitude() + "," + from.getLongitude(), if (null == distance) {
to.getLatitude() + "," + to.getLongitude(), vehicleType); distance = getDistance(from.getLatitude() + "," + from.getLongitude(),
if (null == distance) { to.getLatitude() + "," + to.getLongitude(), vehicleType);
Distance dis = new Distance(); if (null == distance) {
return dis; Distance dis = new Distance();
} else { return dis;
distanceCache.put(key, distance); } else {
} //distanceCache.put(key, distance);
return distance; RedisUtil.set(key, distance);
} else { }
return distance; return distance;
} } else {
} catch (Exception e) { return distance;
Distance dis = new Distance(); }
return dis; } catch (Exception e) {
} Distance dis = new Distance();
} return dis;
}
private static Distance getDistance(String yx1, String yx2, int vehicleType) throws Exception { }
public static String getLocationKey(Location from, Location to, int vehicleType) {
Map<String, String> params = new HashMap<String, String>(); return convertDoubleToStr(from.getLongitude()) + ","
params.put("origins", yx1); + convertDoubleToStr(from.getLatitude()) + ";"
params.put("destinations", yx2); + convertDoubleToStr(to.getLongitude()) + ","
params.put("ak", AK); + convertDoubleToStr(to.getLatitude()) + "|" + vehicleType;
params.put("coord_type", "gcj02"); }
String url = ""; public static String convertDoubleToStr(double value) {
switch (vehicleType) { String[] ss = BigDecimal.valueOf(value).toString().split("\\.");
case 1:
url = URL + "driving?"; if (ss.length == 1) {
break; return ss[0] + ".00000";
case 2: }
params.put("riding_type", "1");// 电动自行车
url = URL + "riding?"; if (ss[1].length() >= 5) {
break; return ss[0] + "." + ss[1].substring(0, 5);
case 3: }
params.put("riding_type", "0");// 普通自行车
url = URL + "riding?"; return ss[0] + "." + StrUtil.padAfter(ss[1], 5, "0");
break; }
case 4:
url = URL + "walking?"; private static Distance getDistance(String yx1, String yx2, int vehicleType) throws Exception {
break;
}
Map<String, String> params = new HashMap<String, String>();
String text = requestGetAK(url, params); params.put("origins", yx1);
// System.out.println(url + " : " + gson.toJson(params) + " : " + text); params.put("destinations", yx2);
BDResult webResult = gson.fromJson(text, BDResult.class); params.put("ak", AK);
float dis = webResult.getResult().get(0).getDistance().getValue() / 1000F; params.put("coord_type", "gcj02");
int time = webResult.getResult().get(0).getDuration().getValue();
String url = "";
Distance d = new Distance(); switch (vehicleType) {
d.setDis(dis); case 1:
d.setTime(time); url = URL + "driving?";
return d; break;
} case 2:
params.put("riding_type", "1");// 电动自行车
/** url = URL + "riding?";
* 默认ak 选择了ak,使用IP白名单校验: 根据您选择的AK已为您生成调用代码 检测到您当前的ak设置了IP白名单校验 break;
* 您的IP白名单中的IP非公网IP,请设置为公网IP,否则将请求失败 请在IP地址为xxxxxxx的计算发起请求,否则将请求失败 case 3:
*/ params.put("riding_type", "0");// 普通自行车
public static String requestGetAK(String strUrl, Map<String, String> param) throws Exception { url = URL + "riding?";
if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) { break;
return ""; case 4:
} url = URL + "walking?";
break;
StringBuffer queryString = new StringBuffer(); }
queryString.append(strUrl);
for (Map.Entry<?, ?> pair : param.entrySet()) { String text = requestGetAK(url, params);
queryString.append(pair.getKey() + "="); // System.out.println(url + " : " + gson.toJson(params) + " : " + text);
// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可 BDResult webResult = gson.fromJson(text, BDResult.class);
queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&"); float dis = webResult.getResult().get(0).getDistance().getValue() / 1000F;
} int time = webResult.getResult().get(0).getDuration().getValue();
if (queryString.length() > 0) { Distance d = new Distance();
queryString.deleteCharAt(queryString.length() - 1); d.setDis(dis);
} d.setTime(time);
return d;
java.net.URL url = new URL(queryString.toString()); }
URLConnection httpConnection = (HttpURLConnection) url.openConnection();
httpConnection.connect(); /**
* 默认ak 选择了ak,使用IP白名单校验: 根据您选择的AK已为您生成调用代码 检测到您当前的ak设置了IP白名单校验
InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream()); * 您的IP白名单中的IP非公网IP,请设置为公网IP,否则将请求失败 请在IP地址为xxxxxxx的计算发起请求,否则将请求失败
BufferedReader reader = new BufferedReader(isr); */
StringBuffer buffer = new StringBuffer(); public static String requestGetAK(String strUrl, Map<String, String> param) throws Exception {
String line; if (strUrl == null || strUrl.length() <= 0 || param == null || param.size() <= 0) {
while ((line = reader.readLine()) != null) { return "";
buffer.append(line); }
}
reader.close(); StringBuffer queryString = new StringBuffer();
isr.close(); queryString.append(strUrl);
return (buffer.toString()); for (Map.Entry<?, ?> pair : param.entrySet()) {
} queryString.append(pair.getKey() + "=");
// 第一种方式使用的 jdk 自带的转码方式 第二种方式使用的 spring 的转码方法 两种均可
@Data queryString.append(URLEncoder.encode((String) pair.getValue(), "UTF-8").replace("+", "%20") + "&");
public static class Distance { }
float dis;
int time; if (queryString.length() > 0) {
} queryString.deleteCharAt(queryString.length() - 1);
}
@Data
static class BDResult { java.net.URL url = new URL(queryString.toString());
List<BDDistance> result; URLConnection httpConnection = (HttpURLConnection) url.openConnection();
} httpConnection.connect();
@Data InputStreamReader isr = new InputStreamReader(httpConnection.getInputStream());
static class BDDistance { BufferedReader reader = new BufferedReader(isr);
Dis distance; StringBuffer buffer = new StringBuffer();
Dur duration; String line;
} while ((line = reader.readLine()) != null) {
buffer.append(line);
@Data }
static class Dis { reader.close();
Float value; isr.close();
} return (buffer.toString());
}
@Data
static class Dur { @Data
Integer value; public static class Distance {
} float dis;
int time;
}
@Data
static class BDResult {
List<BDDistance> result;
}
@Data
static class BDDistance {
Dis distance;
Dur duration;
}
@Data
static class Dis {
Float value;
}
@Data
static class Dur {
Integer value;
}
} }
...@@ -3,7 +3,7 @@ server: ...@@ -3,7 +3,7 @@ server:
dispatch: dispatch:
cron: cron:
expr: 0 9 8-23 * * ? expr: 0 37 8-23 * * ?
next-day-limit: 2 next-day-limit: 2
scheduler: scheduler:
......
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!