Quartz核心Api
官网:
- Quartz是OpenSymphony开源组织在Job scheduling领域的一个开源项目,由Java开发,可以用来执行定时任务,类似于java.util.Timer。Quartz是功能强大的开源作业调度库,几乎可以集成到任何Java应用程序中。Quartz包含许多企业级功能,例如对JTA事务和集群的支持。Quartz作为定时任务组件,既可以单独使用,也可以整合Spring使用。
Quartz Enterprise Job Scheduler
- Scheduler:任务调度器,使任务和触发器关联,统一进行任务的调度
- StdSchedulerFactory:任务调度器工厂,可以创建Scheduler对象
- JobDetail:任务对象
- JobBuilder:任务构建器,用于创建JobDetail对象
- Trigger:触发器对象
- TriggerBuilder:触发器构建器,用于创建Trigger对象
- JobExecutionContext:任务执行的上下文对象,通过此对象可以获取当前执行任务的相关信息,例如JobDetail、Trigger对象都可以获取到
- JobDataMap:保存任务实例的状态信息
- RAMJobStore:此类实现了一个利用RAM作为其存储设备的JobStore,访问速度极快,但是数据却易失,如果需要在程序关闭之前保持真正的持久性,则不应使用此JobStore
- JobStoreTX:通过JDBC将所有数据保存在数据库中
必要依赖
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz</artifactId>
<version>2.3.0</version>
</dependency>
<dependency>
<groupId>org.quartz-scheduler</groupId>
<artifactId>quartz-jobs</artifactId>
<version>2.3.0</version>
</dependency>
数据表
qrtz 开头的表自行寻找
CREATE TABLE `schedule_job` (
`id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL COMMENT 'id',
`bean_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'spring bean名称',
`params` varchar(1000) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '参数',
`cron_expression` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'cron表达式',
`status` tinyint unsigned DEFAULT NULL COMMENT '任务状态 0:暂停 1:正常',
`remark` varchar(255) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '备注',
`business_id` varchar(50) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '业务id:机构id',
`creator` bigint DEFAULT NULL COMMENT '创建者',
`create_date` datetime DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`updater` bigint DEFAULT NULL COMMENT '更新者',
`update_date` datetime DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_create_date` (`create_date`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=COMPACT COMMENT='定时任务';
CREATE TABLE `schedule_job_log` (
`id` bigint NOT NULL COMMENT 'id',
`job_id` bigint NOT NULL COMMENT '任务id',
`bean_name` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT 'spring bean名称',
`params` varchar(2000) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '参数',
`status` tinyint unsigned NOT NULL COMMENT '任务状态 0:失败 1:成功',
`error` varchar(5000) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL COMMENT '失败信息',
`times` int NOT NULL COMMENT '耗时(单位:毫秒)',
`create_date` datetime DEFAULT NULL COMMENT '创建时间',
PRIMARY KEY (`id`) USING BTREE,
KEY `idx_job_id` (`job_id`) USING BTREE,
KEY `idx_create_date` (`create_date`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 ROW_FORMAT=COMPACT COMMENT='定时任务日志';
配置类
SchedulerFactoryBean 放入容器用于创建 Scheduler
/**
* 定时任务配置
*/
@Configuration
public class ScheduleConfig {
@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource) {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setDataSource(dataSource);
//quartz参数
Properties prop = new Properties();
prop.put("org.quartz.scheduler.instanceName", "WitlinkedScheduler");
prop.put("org.quartz.scheduler.instanceId", "AUTO");
//线程池配置
prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
prop.put("org.quartz.threadPool.threadCount", "20");
prop.put("org.quartz.threadPool.threadPriority", "5");
//JobStore配置
prop.put("org.quartz.jobStore.class", "org.quartz.impl.jdbcjobstore.JobStoreTX");
//集群配置
prop.put("org.quartz.jobStore.isClustered", "true");
prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "1");
prop.put("org.quartz.jobStore.misfireThreshold", "12000");
prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
//PostgreSQL数据库,需要打开此注释
//prop.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
factory.setQuartzProperties(prop);
factory.setSchedulerName("pdScheduler");
//延时启动
factory.setStartupDelay(5);
factory.setApplicationContextSchedulerContextKey("applicationContextKey");
//可选,QuartzScheduler 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
factory.setOverwriteExistingJobs(true);
//设置自动启动,默认为true
factory.setAutoStartup(true);
return factory;
}
}
必要工具类
提供了一些常用方法,用于操作调度器 Scheduler
/**
* 定时任务工具类
*
* @author
*/
public class ScheduleUtils {
private final static String JOB_NAME = "TASK_";
/**
* 任务调度参数key
*/
public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY";
/**
* 获取触发器key
*/
public static TriggerKey getTriggerKey(String jobId) {
return TriggerKey.triggerKey(JOB_NAME + jobId);
}
/**
* 获取jobKey
*/
public static JobKey getJobKey(String jobId) {
return JobKey.jobKey(JOB_NAME + jobId);
}
/**
* 获取表达式触发器
*/
public static CronTrigger getCronTrigger(Scheduler scheduler, String jobId) {
try {
return (CronTrigger) scheduler.getTrigger(getTriggerKey(jobId));
} catch (SchedulerException e) {
throw new PdException("getCronTrigger ERROR", e);
}
}
/**
* 创建定时任务
*/
public static void createScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
try {
//构建job信息
JobDetail jobDetail = JobBuilder.newJob(ScheduleJob.class).withIdentity(getJobKey(scheduleJob.getId())).build();
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
.withMisfireHandlingInstructionDoNothing();
//按新的cronExpression表达式构建一个新的trigger
CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(scheduleJob.getId())).withSchedule(scheduleBuilder).build();
//放入参数,运行时的方法可以获取
jobDetail.getJobDataMap().put(JOB_PARAM_KEY, scheduleJob);
scheduler.scheduleJob(jobDetail, trigger);
//暂停任务
if (scheduleJob.getStatus() == ScheduleStatus.PAUSE.getValue()) {
pauseJob(scheduler, scheduleJob.getId());
}
} catch (SchedulerException e) {
throw new PdException("CREATE ERROR", e);
}
}
/**
* 更新定时任务
*/
public static void updateScheduleJob(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
try {
TriggerKey triggerKey = getTriggerKey(scheduleJob.getId());
//表达式调度构建器
CronScheduleBuilder scheduleBuilder = CronScheduleBuilder.cronSchedule(scheduleJob.getCronExpression())
.withMisfireHandlingInstructionDoNothing();
CronTrigger trigger = getCronTrigger(scheduler, scheduleJob.getId());
//按新的cronExpression表达式重新构建trigger
trigger = trigger.getTriggerBuilder().withIdentity(triggerKey).withSchedule(scheduleBuilder).build();
//参数
trigger.getJobDataMap().put(JOB_PARAM_KEY, scheduleJob);
scheduler.rescheduleJob(triggerKey, trigger);
//暂停任务
if (scheduleJob.getStatus() == ScheduleStatus.PAUSE.getValue()) {
pauseJob(scheduler, scheduleJob.getId());
}
} catch (SchedulerException e) {
throw new PdException("UPDATE ERROR", e);
}
}
/**
* 立即执行任务
*/
public static void run(Scheduler scheduler, ScheduleJobEntity scheduleJob) {
try {
//参数
JobDataMap dataMap = new JobDataMap();
dataMap.put(JOB_PARAM_KEY, scheduleJob);
scheduler.triggerJob(getJobKey(scheduleJob.getId()), dataMap);
} catch (SchedulerException e) {
throw new PdException("RUN ERROR", e);
}
}
/**
* 暂停任务
*/
public static void pauseJob(Scheduler scheduler, String jobId) {
try {
scheduler.pauseJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new PdException("PAUSE ERROR", e);
}
}
/**
* 恢复任务
*/
public static void resumeJob(Scheduler scheduler, String jobId) {
try {
scheduler.resumeJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new PdException("RESUME ERROR", e);
}
}
/**
* 删除定时任务
*/
public static void deleteScheduleJob(Scheduler scheduler, String jobId) {
try {
scheduler.deleteJob(getJobKey(jobId));
} catch (SchedulerException e) {
throw new PdException("DELETE ERROR", e);
}
}
}
调度器数据预热
用于项目启动时从定时任务表中查询定时任务信息
@Slf4j
@Component
public class DispatchCommandLineRunner implements CommandLineRunner {
@Autowired
private Scheduler scheduler;
@Autowired
private IScheduleJobService scheduleJobService;
@Override
public void run(String... args) throws Exception {
log.info("定时任务初始化");
List<ScheduleJobEntity> scheduleJobEntities = scheduleJobService.list();
for (ScheduleJobEntity scheduleJob : scheduleJobEntities) {
CronTrigger trigger = ScheduleUtils.getCronTrigger(scheduler, scheduleJob.getId());
if(trigger == null){
ScheduleUtils.createScheduleJob(scheduler,scheduleJob);
} else {
ScheduleUtils.updateScheduleJob(scheduler,scheduleJob);
}
}
}
}
定时任务执行入口
通过继承 QuartzJobBean 重写 executeInternal() 当有定时任务被触发时就会对此函数进行回调,JobExecutionContext 中可以获取任务所需参数。
/**
* 定时任务
*/
public class ScheduleJob extends QuartzJobBean {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
protected void executeInternal(JobExecutionContext context) {
ScheduleJobEntity scheduleJob = (ScheduleJobEntity)context.getMergedJobDataMap().get(ScheduleUtils.JOB_PARAM_KEY);
ScheduleJobLogEntity scheduleJobLog = new ScheduleJobLogEntity();
scheduleJobLog.setBeanName(scheduleJob.getBeanName());
scheduleJobLog.setId(IdUtils.get());
scheduleJobLog.setJobId(scheduleJob.getId());
scheduleJobLog.setParams(scheduleJob.getParams());
scheduleJobLog.setCreateDate(new Date());
System.out.println(new Date() + "定时任务开始执行...,定时任务id:" + scheduleJob.getId());
//任务开始时间
long startTime = System.currentTimeMillis();
try {
Object bean = SpringContextUtils.getBean(scheduleJob.getBeanName());
Method method = bean.getClass().getDeclaredMethod("run", String.class, String.class, String.class, String.class);
method.invoke(bean,scheduleJob.getBusinessId(),scheduleJob.getParams(),scheduleJob.getId(),scheduleJobLog.getId());
long times = System.currentTimeMillis() - startTime;
scheduleJobLog.setTimes((int) times);
scheduleJobLog.setStatus(1);
logger.info("定时任务执行耗时: {}",times);
} catch (Exception e) {
logger.error("任务执行失败,异常信息:{}", e.getMessage());
//任务执行总时长
long times = System.currentTimeMillis() - startTime;
scheduleJobLog.setTimes((int) times);
//任务状态
scheduleJobLog.setStatus(0);
scheduleJobLog.setError(ExceptionUtils.getErrorStackTrace(e));
} finally {
IScheduleJobLogService jobLogService = SpringContextUtils.getBean(IScheduleJobLogService.class);
jobLogService.save(scheduleJobLog);
}
}
}
/**
* Spring Context 工具类
*/
@Component
public class SpringContextUtils implements ApplicationContextAware {
public static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext)
throws BeansException {
SpringContextUtils.applicationContext = applicationContext;
}
public static Object getBean(String name) {
return applicationContext.getBean(name);
}
public static <T> T getBean(Class<T> cls) {
return applicationContext.getBean(cls);
}
public static <T> T getBean(String name, Class<T> requiredType) {
return applicationContext.getBean(name, requiredType);
}
public static boolean containsBean(String name) {
return applicationContext.containsBean(name);
}
public static boolean isSingleton(String name) {
return applicationContext.isSingleton(name);
}
public static Class<? extends Object> getType(String name) {
return applicationContext.getType(name);
}
}
任务处理类
ScheduleJob.executeInternal() 触发后,会通过反射调用 DispatchTask.run() , 对定时任务的业务处理以此类为入口,逻辑在 ITask为前缀的 service 中。
@Slf4j
@Component("dispatchTask")
public class DispatchTask {
@Autowired
private ITaskOrderClassifyService orderClassifyService;
@Autowired
private ITaskTripsSchedulingService truckSchedulingService;
@Autowired
private ITaskRoutePlanningService routePlanningService;
@Autowired
private IBusinessOperationService businessOperationService;
@SneakyThrows
public void run(String businessId, String params, String jobId, String logId) {
String LOGID = businessId + System.currentTimeMillis();
log.info("[{}]TestTask定时任务正在执行,参数为:{},{},{},{}", LOGID, businessId, params, jobId, logId);
// 订单分类
List<OrderClassifyGroupDTO> orderClassifys = orderClassifyService.execute(businessId, jobId, logId);
log.info("[{}] 订单分类完成:{}", LOGID, orderClassifys);
// 路线规划
List<OrderLineSimpleDTO> orderLineSimpleDTOS = routePlanningService.execute(orderClassifys, businessId, jobId, logId, params);
log.info("[{}] 路线规划完成:{}", LOGID, orderLineSimpleDTOS);
// 创建运输任务; 关联运单
Map<String, TaskTransportDTO> transportTaskMap = businessOperationService.createTransportOrderTask(orderLineSimpleDTOS);
log.info("[{}] 运输任务创建完成:{}", LOGID, transportTaskMap);
// 车次 车辆 司机
List<OrderLineTripsTruckDriverDTO> orderLineTripsTruckDriverDTOS = truckSchedulingService.execute(orderLineSimpleDTOS, businessId, jobId, logId, params);
log.info("[{}] 规划车次车辆司机:{}", LOGID, orderLineTripsTruckDriverDTOS);
// 完善运输任务信息; 创建司机作业任务;
businessOperationService.updateTransportTask(orderLineTripsTruckDriverDTOS, transportTaskMap);
log.info("[{}] 安排车次车辆司机,当前机构调度结束!!!!!", LOGID);
}
}
处理定时任务service部分代码
用于生成订单分类数据
/**
* 订单分类实现类
*/
@Service
@Slf4j
public class TaskOrderClassifyServiceImpl implements ITaskOrderClassifyService {
@Autowired
private OrderFeign orderFeign;
@Autowired
private AgencyScopeFeign agencyScopeFeign;
@Autowired
private IOrderClassifyService orderClassifyService;
@Autowired
private IOrderClassifyOrderService orderClassifyOrderService;
/**
* 订单分类核心逻辑
* @param agencyId 机构id(网点或者转运中心的id)
* @param jobId 定时任务id
* @param logId 日志id
* @return
*/
@Override
public List<OrderClassifyGroupDTO> execute(String agencyId, String jobId, String logId) {
//存放当前机构的订单
List<OrderClassifyDTO> orderClassifyDTOList = new ArrayList<>();
//存放分类后的订单信息
List<OrderClassifyGroupDTO> orderClassifyGroupDTOList = new ArrayList<>();
//将新订单存入集合中
orderClassifyDTOList.addAll(buildNewOrder(agencyId));
//将中转订单放入集合中
orderClassifyDTOList.addAll(buildTransferOrder(agencyId));
//对分类后的订单进行分组
Map<String, List<OrderClassifyDTO>> listMap = orderClassifyDTOList.stream().collect(Collectors.groupingBy(OrderClassifyDTO::groupBy));
OrderClassifyGroupDTO.OrderClassifyGroupDTOBuilder orderClassifyGroupDTOBuilder = OrderClassifyGroupDTO.builder();
//生成分类结果数据
listMap.forEach((k,v)->{
orderClassifyGroupDTOBuilder.key(k);
orderClassifyGroupDTOBuilder.orders(v.stream().map(OrderClassifyDTO::getOrder).collect(Collectors.toList()));
orderClassifyGroupDTOList.add(orderClassifyGroupDTOBuilder.build());
});
//保存分类结果数据
saveRecord(orderClassifyGroupDTOList,jobId,logId);
return orderClassifyGroupDTOList;
}
/**
* 保存订单分类结果
* @param orderClassifyGroupDTOS
* @param jobId
* @param logId
*/
private void saveRecord(List<OrderClassifyGroupDTO> orderClassifyGroupDTOS, String jobId, String logId) {
orderClassifyGroupDTOS.forEach(item -> {
if(item.isNew()){
log.info("新订单 保存分组信息");
OrderClassifyEntity classifyEntity = new OrderClassifyEntity();
classifyEntity.setClassify(item.getKey());
classifyEntity.setTotal(item.getOrders().size());
if (!classifyEntity.getClassify().equals("ERROR")) {
classifyEntity.setStartAgencyId(item.getStartAgencyId());
classifyEntity.setEndAgencyId(item.getEndAgencyId());
}
classifyEntity.setId(IdUtils.get());
classifyEntity.setJobId(jobId);
classifyEntity.setJobLogId(logId);
classifyEntity.setCreateDate(new Date());
List<OrderClassifyOrderEntity> classifyOrderEntities = item.getOrders().stream().map((order) -> {
OrderClassifyOrderEntity orderClassifyOrderEntity = new OrderClassifyOrderEntity();
orderClassifyOrderEntity.setOrderId(order.getId());
orderClassifyOrderEntity.setOrderClassifyId(classifyEntity.getId());
orderClassifyOrderEntity.setId(IdUtils.get());
return orderClassifyOrderEntity;
}).collect(Collectors.toList());
orderClassifyOrderService.saveBatch(classifyOrderEntities);
orderClassifyService.save(classifyEntity);
item.setId(classifyEntity.getId());
} else {
log.info("中转订单,查询分组信息");
//中转订单
List<String> orderIdList = item.getOrders().stream().map(Order::getId).collect(Collectors.toList());
LambdaQueryWrapper<OrderClassifyOrderEntity> orderEntityLambdaQueryWrapper = new LambdaQueryWrapper<>();
orderEntityLambdaQueryWrapper.in(OrderClassifyOrderEntity::getOrderId,orderIdList);
List<OrderClassifyOrderEntity> orderEntities = orderClassifyOrderService.list(orderEntityLambdaQueryWrapper);
Set<String> classifyEntitySet = orderEntities.stream().map(OrderClassifyOrderEntity::getOrderClassifyId).collect(Collectors.toSet());
if(ObjectUtil.isEmpty(classifyEntitySet)){
exceptionHappend("查询订单异常");
}
item.setId(classifyEntitySet.iterator().next());
}
});
}
/**
*查询中转订单
* @param agencyId
* @return
*/
private List<OrderClassifyDTO> buildTransferOrder(String agencyId) {
//1.获取中转订单信息
OrderSearchDTO orderSearchDTO = new OrderSearchDTO();
orderSearchDTO.setStatus(OrderStatus.IN_TRANSIT.getCode());
orderSearchDTO.setCurrentAgencyId(agencyId);
List<Order> orders = orderFeign.list(orderSearchDTO);
//2.封装订单分类数据
OrderClassifyDTO.OrderClassifyDTOBuilder builder = OrderClassifyDTO.builder();
List<OrderClassifyDTO> orderClassifyDTOS = orders.stream().map((item) -> {
builder.startAgencyId(getStartAgencyId(item));
builder.endAgencyId(getEndAgencyId(item));
builder.order(item);
builder.orderType(item.getOrderType());
return builder.build();
}).collect(Collectors.toList());
return orderClassifyDTOS;
}
/**
* 根据订单获得起始机构id
* @param order
* @return
*/
private String getStartAgencyId(Order order) {
//1.获取地址描述
String address = senderFullAddress(order);
if (StringUtils.isBlank(address)) {
exceptionHappend("下单时发货地址不能为空");
}
//2.获取坐标
String location = EntCoordSyncJob.getCoordinate(address);
log.info("订单发货地址和坐标-->" + address + "--" + location);
if (StringUtils.isBlank(location)) {
exceptionHappend("下单时发货地址不能为空");
}
//3.获取区域信息
Map position = EntCoordSyncJob.getLocationByPosition(location);
if (ObjectUtils.isEmpty(position)) {
exceptionHappend("根据地图获取区域信息为空");
}
//4.查询区域信息
String adcode = position.getOrDefault("adcode", "").toString();
R<Area> r = areaApi.getByCode(adcode + "000000");
if(!r.getIsSuccess()){
Result.error(r.getMsg());
}
//5.查询网点信息
Area area = r.getData();
if (area == null) {
exceptionHappend("区域编码:" + adcode + "区域信息未从库中获取到");
}
String areaID = area.getId().toString();
if (!order.getSenderCountyId().equals(areaID)) {
exceptionHappend("参数中发货区域id和坐标计算出真实区域id不同,数据不合法");
}
List<AgencyScopeDto> agencyScope = agencyScopeFeign.findAllAgencyScope(areaID, null, null, null);
if(agencyScope == null || agencyScope.size() == 0){
exceptionHappend("根据区域无法从机构范围获取网点信息列表");
}
Result result = this.caculate(agencyScope, location);
return result.get("agencyId").toString();
}
/**
* 获得发件人详细地址信息
* @param order
* @return
*/
@SneakyThrows
private String senderFullAddress(Order order) {
Long province = Long.valueOf(order.getSenderProvinceId());
Long city = Long.valueOf(order.getSenderCityId());
Long county = Long.valueOf(order.getSenderCountyId());
Set<Long> set = new HashSet<>();
set.add(province);
set.add(city);
set.add(county);
CompletableFuture<Map<Long, Area>> completableFuture = PdCompletableFuture.areaMapFuture(areaApi, null, set);
Map<Long, Area> areaMap = completableFuture.get();
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append(areaMap.get(province).getName());
stringBuffer.append(areaMap.get(city).getName());
stringBuffer.append(areaMap.get(county).getName());
return stringBuffer.toString();
}
/**
* 获取指定机构下的新订单
* @param agencyId
* @return
*/
private List<OrderClassifyDTO> buildNewOrder(String agencyId) {
//1.查询订单信息
OrderSearchDTO orderSearchDTO = new OrderSearchDTO();
//订单状态为网点入库
orderSearchDTO.setStatus(OrderStatus.OUTLETS_WAREHOUSE.getCode());
orderSearchDTO.setCurrentAgencyId(agencyId);
List<Order> orders = orderFeign.list(orderSearchDTO);
log.info("查询[网点入库]状态订单:{} 条", orders.size());
//2.组装订单分类信息
OrderClassifyDTO.OrderClassifyDTOBuilder builder = OrderClassifyDTO.builder();
List<OrderClassifyDTO> classifyDTOS = orders.stream().map((item) -> {
builder.order(item);
builder.startAgencyId(agencyId);
builder.endAgencyId(getEndAgencyId(item));
builder.orderType(item.getOrderType());
return builder.build();
}).collect(Collectors.toList());
log.info("订单分类:首次发出订单{}条", classifyDTOS.size());
return classifyDTOS;
}
/**
* 抛出异常
* @param msg
*/
private void exceptionHappend(String msg){
try {
throw new Exception(msg);
}catch (Exception e){
e.printStackTrace();
}
}
/**
* 获取目的地网点id
* @param order
* @return
*/
private String getEndAgencyId(Order order) {
//1.获取地址信息
String address = receiverFullAddress(order);
if(StringUtils.isEmpty(address)){
exceptionHappend("下单时收货地址不能为空");
}
//2.获取地址
String location = EntCoordSyncJob.getCoordinate(address);
log.info("订单收货地址和坐标-->" + address + "--" + location);
if(StringUtils.isEmpty(location)){
exceptionHappend("下单时收货地址不能正确");
}
//3.获取区域信息
Map map = EntCoordSyncJob.getLocationByPosition(location);
if(ObjectUtil.isEmpty(map)){
exceptionHappend("根据地图获取区域信息为空");
}
//4.获取区域编码
String adcode = map.getOrDefault("adcode", "").toString();
R<Area> r = areaApi.getByCode(adcode + "000000");
Area area = r.getData();
if(area == null){
exceptionHappend("区域编码:" + adcode + "区域信息未从库中获取到");
}
//5.校验区域编码是否一致
String areaId = String.valueOf(area.getId());
if(!order.getReceiverAddressId().equals(areaId)){
exceptionHappend("区域编码:" + adcode + "区域信息未从库中获取到");
}
//6.获取网点信息列表
List<AgencyScopeDto> agencyScope = agencyScopeFeign.findAllAgencyScope(areaId, null, null, null);
if(agencyScope == null || agencyScope.size() == 0){
exceptionHappend("根据区域无法从机构范围获取网点信息列表");
}
//7.计算距离最近的网点
Result res = this.caculate(agencyScope, location);
return res.get("agencyId").toString();
}
/**
* 从给定网点中查找覆盖指定点的网点
* @param agencyScopes
* @param location
* @return
*/
private Result caculate(List<AgencyScopeDto> agencyScopes,String location) {
try {
Map agencyMap = Maps.newHashMap();
for (AgencyScopeDto agencyScopeDto : agencyScopes) {
List<List<Map>> points = agencyScopeDto.getMutiPoints();
for (List<Map> point : points) {
//注释掉的代码有bug,虽然说距离最近,但可能这个网点不负责这片区域
// String p = getPoint(map);
// Double distance = EntCoordSyncJob.getDistance(location, p);
// Double preDistance = (Double) agencyMap.get(agencyScopeDto.getAgencyId());
// if(preDistance == null || distance < preDistance){
// agencyMap.put(agencyScopeDto.getAgencyId(),distance);
// }
String[] originArray = location.split(",");
boolean inScope = EntCoordSyncJob.isInScope(point, Double.parseDouble(originArray[0]), Double.parseDouble(originArray[1]));
if(inScope){
return Result.ok().put("agencyId",agencyScopeDto.getAgencyId());
}
}
}
// List<Map.Entry<String,Double>> list= new ArrayList<>(agencyMap.entrySet());
// list.sort(Comparator.comparingDouble(Map.Entry::getValue));
// return Result.ok().put("agencyId",list.get(0).getKey());
} catch (Exception e) {
log.error("获取最短距离网点失败,error:{}",e.getMessage());
return Result.error(5000, "获取最短距离网点失败");
}
return Result.error(5000, "获取所属网点失败");
}
/**
* 获取坐标值
* @param map
* @return
*/
private String getPoint(Map map){
String lng = map.get("lng").toString();
String lat = map.get("lat").toString();
return lng + "," + lat;
}
public static void main(String[] args) {
Path2D.Double generalPath = new Path2D.Double();
//绘制区域范围
generalPath.moveTo(0,0);
generalPath.lineTo(1,0);
generalPath.lineTo(1,1);
generalPath.lineTo(0,1);
generalPath.lineTo(0,0);
generalPath.closePath();
//判断指定点是否在上面的区域范围内
boolean contains = generalPath.contains(0.1, 0.1);
System.out.println(contains);
}
@Autowired
private AreaApi areaApi;
/**
* 根据订单获取对应的完整收件人地址信息
* @param order
* @return
*/
@SneakyThrows
private String receiverFullAddress(Order order) {
Long province = Long.valueOf(order.getReceiverProvinceId());
Long city = Long.valueOf(order.getReceiverCityId());
Long county = Long.valueOf(order.getReceiverCountyId());
Set<Long> set = new HashSet<>();
set.add(province);
set.add(city);
set.add(county);
CompletableFuture<Map<Long, Area>> mapCompletableFuture = PdCompletableFuture.areaMapFuture(areaApi, null, set);
Map<Long, Area> longAreaMap = mapCompletableFuture.get();
StringBuffer buffer = new StringBuffer();
buffer.append(longAreaMap.get(province).getName());
buffer.append(longAreaMap.get(city).getName());
buffer.append(longAreaMap.get(county).getName());
buffer.append(order.getReceiverAddress());
return buffer.toString();
}
}
操作Quartz可视化接口
controller
/**
* 定时任务
*
* @author
*/
@RestController
@RequestMapping("/schedule")
@Api(tags = "定时任务")
public class ScheduleJobController {
private static final List<Integer> ORG_TYPE = ImmutableList.of(OrgType.BUSINESS_HALL.getType(), OrgType.TOP_TRANSFER_CENTER.getType(), OrgType.TOP_TRANSFER_CENTER.getType()).asList();
@Autowired
private IScheduleJobService scheduleJobService;
@Autowired
private OrgApi orgApi;
@GetMapping("page")
@ApiOperation("分页")
@ApiImplicitParams({
@ApiImplicitParam(name = "page", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "pageSize", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "name", value = "name", paramType = "query", dataType = "String")
})
public R<List<OrgJobTreeDTO>> page(@ApiIgnore @RequestParam Map<String, Object> params) {
List<OrgJobTreeDTO> tree = scheduleJobService.page(params);
return R.success(tree);
}
@GetMapping("{id}")
@ApiOperation("信息")
public ScheduleJobDTO info(@PathVariable("id") String id) {
ScheduleJobDTO schedule = scheduleJobService.get(id);
return schedule;
}
@GetMapping("dispatch/{id}")
@ApiOperation("调度信息")
public Result dispatchInfo(@PathVariable("id") String id) {
LambdaQueryWrapper<ScheduleJobEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ScheduleJobEntity::getBusinessId, id);
ScheduleJobEntity scheduleJobEntity = scheduleJobService.getOne(wrapper);
if (scheduleJobEntity == null) {
return Result.error(404, "机构没有任务信息");
}
ScheduleJobDTO schedule = new ScheduleJobDTO();
BeanUtils.copyProperties(scheduleJobEntity, schedule);
return Result.ok().put("data", schedule);
}
@PostMapping
@ApiOperation("保存")
public Result save(@RequestBody ScheduleJobDTO dto) {
scheduleJobService.save(dto);
return Result.ok();
}
@PostMapping("dispatch")
@ApiOperation("保存或修改")
public Result dispatch(@RequestBody ScheduleJobDTO dto) {
String businessId = dto.getBusinessId();
R<Org> orgR = orgApi.get(Long.valueOf(businessId));
Integer orgType = orgR.getData().getOrgType();
if (!ORG_TYPE.contains(orgType)) {
return Result.error(400, "无法给转运中心以上的机构增加调度任务");
}
if (StringUtils.isNotBlank(dto.getId())) {
dto.setUpdateDate(new Date());
scheduleJobService.update(dto);
return Result.ok();
} else {
dto.setId(IdUtils.get());
dto.setBeanName("dispatchTask");
dto.setCreateDate(new Date());
scheduleJobService.save(dto);
return Result.ok();
}
}
@PutMapping
@ApiOperation("修改")
public Result update(@RequestBody ScheduleJobDTO dto) {
scheduleJobService.update(dto);
return Result.ok();
}
@DeleteMapping
@ApiOperation("删除")
public Result delete(@RequestBody String[] ids) {
scheduleJobService.deleteBatch(ids);
return Result.ok();
}
@PutMapping("/run/{id}")
@ApiOperation("立即执行")
public Result run(@PathVariable String id) {
scheduleJobService.run(new String[]{id});
return Result.ok();
}
@PutMapping("/run")
@ApiOperation("立即执行")
public Result run(@RequestBody String[] ids) {
scheduleJobService.run(ids);
return Result.ok();
}
@PutMapping("/pause/{id}")
@ApiOperation("暂停")
public Result pause(@PathVariable String id) {
scheduleJobService.pause(new String[]{id});
return Result.ok();
}
@PutMapping("/pause")
@ApiOperation("暂停")
public Result pause(@RequestBody String[] ids) {
scheduleJobService.pause(ids);
return Result.ok();
}
@PutMapping("/resume/{id}")
@ApiOperation("恢复")
public Result resume(@PathVariable String id) {
scheduleJobService.resume(new String[]{id});
return Result.ok();
}
@PutMapping("/resume")
@ApiOperation("恢复")
public Result resume(@RequestBody String[] ids) {
scheduleJobService.resume(ids);
return Result.ok();
}
}
service
@Service
public class ScheduleJobServiceImpl extends ServiceImpl<ScheduleJobMapper, ScheduleJobEntity> implements IScheduleJobService {
@Autowired
private Scheduler scheduler;
@Autowired
private OrgApi orgApi;
@Override
public List<OrgJobTreeDTO> page(Map<String, Object> params) {
R<List<OrgTreeDTO>> orgTree = orgApi.tree("", true);
List<OrgTreeDTO> orgTreeDTOS = orgTree.getData();
List<ScheduleJobEntity> schedulerEntity = baseMapper.selectList(null);
Map<String, ScheduleJobEntity> schedulerMap = schedulerEntity.stream().collect(Collectors.toMap(ScheduleJobEntity::getBusinessId, item -> item));
List<OrgJobTreeDTO> orgJobTreeDTOS = new ArrayList<>();
mergeOrgJob(orgJobTreeDTOS, orgTreeDTOS, schedulerMap);
return orgJobTreeDTOS;
}
private void mergeOrgJob(List<OrgJobTreeDTO> orgJobTreeDTOS, List<OrgTreeDTO> orgTreeDTOS, Map<String, ScheduleJobEntity> schedulerMap) {
orgTreeDTOS.forEach(item -> {
OrgJobTreeDTO orgJobTreeDTO = new OrgJobTreeDTO();
BeanUtils.copyProperties(item, orgJobTreeDTO);
Long orgId = orgJobTreeDTO.getId();
ScheduleJobEntity schedulerDto = schedulerMap.get(orgId.toString());
if (schedulerDto != null) {
orgJobTreeDTO.setCronExpression(schedulerDto.getCronExpression());
orgJobTreeDTO.setJobId(schedulerDto.getId());
orgJobTreeDTO.setParams(schedulerDto.getParams());
orgJobTreeDTO.setRemark(schedulerDto.getRemark());
orgJobTreeDTO.setJobStatus(schedulerDto.getStatus());
}
orgJobTreeDTOS.add(orgJobTreeDTO);
});
}
@Override
public ScheduleJobDTO get(String id) {
ScheduleJobEntity entity = baseMapper.selectById(id);
return ConvertUtils.sourceToTarget(entity, ScheduleJobDTO.class);
}
@Override
public ScheduleJobDTO getByOrgId(String id) {
LambdaQueryWrapper<ScheduleJobEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(ScheduleJobEntity::getBusinessId, id);
ScheduleJobEntity entity = baseMapper.selectOne(wrapper);
return ConvertUtils.sourceToTarget(entity, ScheduleJobDTO.class);
}
private QueryWrapper<ScheduleJobEntity> getWrapper(Map<String, Object> params) {
String beanName = (String) params.get("beanName");
QueryWrapper<ScheduleJobEntity> wrapper = new QueryWrapper<>();
wrapper.like(StringUtils.isNotBlank(beanName), "bean_name", beanName);
return wrapper;
}
@Override
@Transactional(rollbackFor = Exception.class)
public void save(ScheduleJobDTO dto) {
ScheduleJobEntity entity = ConvertUtils.sourceToTarget(dto, ScheduleJobEntity.class);
entity.setStatus(ScheduleStatus.NORMAL.getValue());
baseMapper.insert(entity);
ScheduleUtils.createScheduleJob(scheduler, entity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void update(ScheduleJobDTO dto) {
ScheduleJobEntity entity = this.getById(dto.getId());
BeanUtils.copyProperties(dto, entity, ConvertUtils.getNullPropertyNames(dto));
ScheduleUtils.updateScheduleJob(scheduler, entity);
this.updateById(entity);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void deleteBatch(String[] ids) {
for (String id : ids) {
ScheduleUtils.deleteScheduleJob(scheduler, id);
}
//删除数据
baseMapper.deleteBatchIds(Arrays.asList(ids));
}
@Override
public int updateBatch(String[] ids, int status) {
Map<String, Object> map = new HashMap<>(2);
map.put("ids", ids);
map.put("status", status);
ScheduleJobEntity scheduleJobEntity = new ScheduleJobEntity();
scheduleJobEntity.setStatus(status);
LambdaQueryWrapper<ScheduleJobEntity> wrapper = new LambdaQueryWrapper();
wrapper.in(ScheduleJobEntity::getId, ids);
return baseMapper.update(scheduleJobEntity, wrapper);
}
@Override
@Transactional(rollbackFor = Exception.class)
public void run(String[] ids) {
for (String id : ids) {
ScheduleUtils.run(scheduler, baseMapper.selectById(id));
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void pause(String[] ids) {
for (String id : ids) {
ScheduleUtils.pauseJob(scheduler, id);
}
updateBatch(ids, ScheduleStatus.PAUSE.getValue());
}
@Override
@Transactional(rollbackFor = Exception.class)
public void resume(String[] ids) {
for (String id : ids) {
ScheduleUtils.resumeJob(scheduler, id);
}
updateBatch(ids, ScheduleStatus.NORMAL.getValue());
}
}
日志接口
/**
* 定时任务日志
*
* @author
*/
@Slf4j
@RestController
@RequestMapping("/scheduleLog")
@Api(tags = "定时任务日志")
public class ScheduleJobLogController {
@Autowired
private IScheduleJobLogService scheduleJobLogService;
@Autowired
private IScheduleJobService scheduleJobService;
@Autowired
private OrgApi orgApi;
@Autowired
private IOrderClassifyService orderClassifyService;
@Autowired
private IOrderClassifyAttachService orderClassifyAttachService;
@Autowired
private ICacheLineUseService cacheLineUseService;
@Autowired
private ICacheLineService cacheLineService;
@Autowired
private ICacheLineDetailService cacheLineDetailService;
@Autowired
private TransportLineFeign transportLineFeign;
@Autowired
private TransportTripsFeign transportTripsFeign;
@Autowired
private UserApi userApi;
@Autowired
private TruckFeign truckFeign;
@GetMapping("page")
@ApiOperation("分页")
@ApiImplicitParams({
@ApiImplicitParam(name = "jobId", value = "jobId", paramType = "query", dataType = "String"),
@ApiImplicitParam(name = "orgId", value = "orgId", paramType = "query", dataType = "String")
})
public PageResponse<ScheduleJobLogDTO> page(@ApiIgnore @RequestParam Map<String, Object> params) {
if (!params.containsKey("page")) {
params.put("page", 1);
}
if (!params.containsKey("pageSize")) {
params.put("pageSize", 10);
}
if (!params.containsKey("jobId")) {
String orgId = params.get("orgId").toString();
ScheduleJobDTO scheduleJobDto = scheduleJobService.getByOrgId(orgId);
params.put("jobId", scheduleJobDto.getId());
}
IPage<ScheduleJobLogEntity> page = scheduleJobLogService.page(params);
List<ScheduleJobLogDTO> newItems = page.getRecords().stream().map(item -> {
ScheduleJobLogDTO scheduleJobLogDTO = new ScheduleJobLogDTO();
BeanUtils.copyProperties(item, scheduleJobLogDTO);
return scheduleJobLogDTO;
}).collect(Collectors.toList());
return PageResponse.<ScheduleJobLogDTO>builder()
.page(Integer.valueOf(String.valueOf(page.getCurrent())))
.pagesize(Integer.valueOf(String.valueOf(page.getSize())))
.pages(page.getPages())
.counts(page.getTotal())
.items(newItems)
.build();
}
@SneakyThrows
@GetMapping("{id}")
@ApiOperation("信息")
public ScheduleJobLogDTO info(@PathVariable("id") Long id) {
ScheduleJobLogDTO logDto = scheduleJobLogService.get(id);
// 组合 订单分组等信息
List<OrderClassifyEntity> orderClassifyEntities = orderClassifyService.findByJobLogId(logDto.getId());
Set<String> agencySet = new HashSet<>();
agencySet.addAll(orderClassifyEntities.stream().map(item -> item.getStartAgencyId()).collect(Collectors.toSet()));
agencySet.addAll(orderClassifyEntities.stream().map(item -> item.getEndAgencyId()).collect(Collectors.toSet()));
CompletableFuture<Map<Long, Org>> agnecyMapFuture = PdCompletableFuture.agencyMapFuture(orgApi, null, agencySet, null);
Map<Long, Org> agencyMap = agnecyMapFuture.get();
List<OrderClassifyLogDTO> orderClassifyLogDTOS = orderClassifyEntities.stream().map(item -> {
OrderClassifyLogDTO orderClassifyLogDTO = new OrderClassifyLogDTO();
BeanUtils.copyProperties(item, orderClassifyLogDTO);
if (StringUtils.isNotEmpty(orderClassifyLogDTO.getStartAgencyId())) {
orderClassifyLogDTO.setStartAgency(agencyMap.get(Long.parseLong(orderClassifyLogDTO.getStartAgencyId())).getName());
}
if (StringUtils.isNotBlank(orderClassifyLogDTO.getEndAgencyId())) {
orderClassifyLogDTO.setEndAgency(agencyMap.get(Long.parseLong(orderClassifyLogDTO.getEndAgencyId())).getName());
}
buildTransportLine(item, orderClassifyLogDTO);
buildTripsTruckDriver(item, orderClassifyLogDTO);
return orderClassifyLogDTO;
}).collect(Collectors.toList());
logDto.setOrderClassifyLogDTOS(orderClassifyLogDTOS);
return logDto;
}
/**
* 获取当前使用的车次 车辆 司机信息
*
* @param item
* @param orderClassifyLogDTO
*/
@SneakyThrows
private void buildTripsTruckDriver(OrderClassifyEntity item, OrderClassifyLogDTO orderClassifyLogDTO) {
LambdaQueryWrapper<OrderClassifyAttachEntity> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(OrderClassifyAttachEntity::getOrderClassifyId, item.getId());
wrapper.orderByAsc(OrderClassifyAttachEntity::getCreateDate);
List<OrderClassifyAttachEntity> orderClassifyAttachs = orderClassifyAttachService.list(wrapper);
Set<String> tripsIdSet = orderClassifyAttachs.stream().map(OrderClassifyAttachEntity::getTripsId).collect(Collectors.toSet());
Set<String> truckIdSet = orderClassifyAttachs.stream().map(OrderClassifyAttachEntity::getTruckId).collect(Collectors.toSet());
Set<String> driverIdSet = orderClassifyAttachs.stream().map(OrderClassifyAttachEntity::getDriverId).collect(Collectors.toSet());
CompletableFuture<Map<String, TransportTripsDto>> tripsMapFuture = PdCompletableFuture.tripsMapFuture(transportTripsFeign, tripsIdSet);
CompletableFuture<Map<String, TruckDto>> truckMapFuture = PdCompletableFuture.truckMapFuture(truckFeign, truckIdSet);
CompletableFuture<Map<Long, User>> driverMapFuture = PdCompletableFuture.driverMapFuture(userApi, driverIdSet);
Set<String> tripsSet = new LinkedHashSet<>();
Set<String> truckSet = new LinkedHashSet<>();
Set<String> driverSet = new LinkedHashSet<>();
Map<String, TransportTripsDto> tripsMap = tripsMapFuture.get();
Map<String, TruckDto> truckMap = truckMapFuture.get();
Map<Long, User> driverMap = driverMapFuture.get();
for (OrderClassifyAttachEntity orderClassifyAttach : orderClassifyAttachs) {
tripsSet.add(tripsMap.get(orderClassifyAttach.getTripsId()).getName());
truckSet.add(truckMap.get(orderClassifyAttach.getTruckId()).getLicensePlate());
driverSet.add(driverMap.get(Long.parseLong(orderClassifyAttach.getDriverId())).getName());
}
orderClassifyLogDTO.setTripsSet(tripsSet);
orderClassifyLogDTO.setTruckSet(truckSet);
orderClassifyLogDTO.setDriverSet(driverSet);
}
/**
* 构建当前分类的订单经过的全部机构 和 全部的线路
*
* @param item
* @param orderClassifyLogDTO
*/
@SneakyThrows
private void buildTransportLine(OrderClassifyEntity item, OrderClassifyLogDTO orderClassifyLogDTO) {
CacheLineUseEntity cacheLineUseEntity = cacheLineUseService.getByOrderClassifyId(item.getId());
Set<String> lineSet = new LinkedHashSet<>();
Set<String> transportLineSet = new LinkedHashSet<>();
if (cacheLineUseEntity != null) {
CacheLineEntity cacheLineEntity = cacheLineService.getById(cacheLineUseEntity.getCacheLineId());
List<CacheLineDetailEntity> cacheLineDetailEntities = cacheLineDetailService.findByCacheLineId(cacheLineUseEntity.getCacheLineId());
Set<String> transportLineIdSet = cacheLineDetailEntities.stream().map(cacheLineDetailEntity -> cacheLineDetailEntity.getTransportLineId()).collect(Collectors.toSet());
CompletableFuture<Map<String, TransportLineDto>> transportLineMapFuture = PdCompletableFuture.transportLineIdMapFuture(transportLineFeign, transportLineIdSet);
Set<String> agencySet = new HashSet<>();
agencySet.add(cacheLineEntity.getStartAgencyId());
agencySet.add(cacheLineEntity.getEndAgencyId());
agencySet.addAll(cacheLineDetailEntities.stream().map(cacheLineDetailEntity -> cacheLineDetailEntity.getStartAgencyId()).collect(Collectors.toSet()));
agencySet.addAll(cacheLineDetailEntities.stream().map(cacheLineDetailEntity -> cacheLineDetailEntity.getEndAgencyId()).collect(Collectors.toSet()));
CompletableFuture<Map<Long, Org>> agnecyMapFu = PdCompletableFuture.agencyMapFuture(orgApi, null, agencySet, null);
Map<String, TransportLineDto> transportLineMap = transportLineMapFuture.get();
Map<Long, Org> agency = agnecyMapFu.get();
cacheLineDetailEntities.forEach(cacheLineDetailEntity -> {
CacheLineDetailDTO cacheLineDetailDTO = new CacheLineDetailDTO();
BeanUtils.copyProperties(cacheLineDetailEntity, cacheLineDetailDTO);
if (StringUtils.isNotEmpty(cacheLineDetailDTO.getStartAgencyId())) {
cacheLineDetailDTO.setStartAgency(agency.get(Long.parseLong(cacheLineDetailDTO.getStartAgencyId())).getName());
}
if (StringUtils.isNotBlank(cacheLineDetailDTO.getEndAgencyId())) {
cacheLineDetailDTO.setEndAgency(agency.get(Long.parseLong(cacheLineDetailDTO.getEndAgencyId())).getName());
}
transportLineSet.add(transportLineMap.get(cacheLineDetailDTO.getTransportLineId()).getName());
lineSet.add(cacheLineDetailDTO.getStartAgency());
lineSet.add(cacheLineDetailDTO.getEndAgency());
});
orderClassifyLogDTO.setTransportLineSet(transportLineSet);
orderClassifyLogDTO.setLineSet(lineSet);
CacheLineDTO cacheLineDTO = new CacheLineDTO();
BeanUtils.copyProperties(cacheLineEntity, cacheLineDTO);
orderClassifyLogDTO.setCacheLineDTO(cacheLineDTO);
}
}
}