当前位置: 首页 > news >正文

《神领物流》day07-线路规划之线路管理_完整代码【简单易懂注释版】

目录

三十六、线路管理之新增路线(上)

1.TransportLineController.java

2.interface TransportLineService

3.TransportLineServiceImpl.java

三十七、线路管理之新增路线(下)

1.TransportLineServiceImpl.java

三十八、线路管理之查询路线数量

1.interface TransportLineRepository

2.TransportLineRepositoryImpl.java

三十九、线路管理之创建路线

1.TransportLineController.java

2.interface TransportLineService

3.TransportLineServiceImpl.java

4.interface TransportLineRepository

5.TransportLineRepositoryImpl.java

6.interface TransportLineRepository

7.TransportLineRepositoryImpl.java

四十、线路管理之查询路线

1.TransportLineController.java

2.interface TransportLineService

3.TransportLineServiceImpl.java

4.interface TransportLineRepository

5.TransportLineRepositoryImpl.java

四十一、线路成本

1.CostConfigurationController.java

2.interface CostConfigurationService

3.CostConfigurationServiceImpl.java

4.TransportLineServiceImpl.java

四十二、调度策略规划路线

1.DispatchConfigurationController.java

2.interface DispatchConfigurationService

3.DispatchConfigurationServiceImpl.java

4.TransportLineServiceImpl.java

四十三、课堂练习-删除路线

1.TransportLineController.java

2.interface TransportLineService

3.TransportLineServiceImpl.java

4.interface TransportLineRepository

5.TransportLineRepositoryImpl.java

四十四、课堂练习-根据id和ids查询路线

1.TransportLineController.java

2.interface TransportLineService

3.TransportLineServiceImpl.java

4.interface TransportLineRepository

5.TransportLineRepositoryImpl.java

四十五、课堂练习-更新路线

1.TransportLineController.java

2.interface TransportLineService

3.TransportLineServiceImpl.java

4.interface TransportLineRepository

5.TransportLineRepositoryImpl.java

四十六、课堂练习-转运节点优先规划+成本优先规划

1.TransportLineController.java

2.interface TransportLineService

3.TransportLineServiceImpl.java

4.interface TransportLineRepository

5.TransportLineRepositoryImpl.java


三十六、线路管理之新增路线(上)

1.TransportLineController.java

package com.sl.transport.controller;/*** 新增路线** @param transportLineDTO 路线数据* @return 是否成功*/@ApiOperation(value = "新增路线", notes = "新增路线,干线:起点终点无顺序,支线:起点必须是二级转运中心,接驳路线:起点必须是网点")@PostMappingpublic void createLine(@RequestBody TransportLineDTO transportLineDTO) {TransportLine transportLine = TransportLineUtils.toEntity(transportLineDTO);Boolean result = this.transportLineService.createLine(transportLine);if (!result) {throw new SLException("新增路线失败!", HttpStatus.INTERNAL_SERVER_ERROR.value());}}

2.interface TransportLineService

package com.sl.transport.service;/*** 新增路线** @param transportLine 路线数据* @return 是否成功*/Boolean createLine(TransportLine transportLine);

3.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 新增路线** @param transportLine 路线数据* @return 是否成功*/@Overridepublic Boolean createLine(TransportLine transportLine) {// 创建路线,判断是否重复,判断起点终点是否相同,设置路线信息(成本、距离、时间)// 1.路线类型,类型必须符合要求的,不符合抛出异常TransportLineEnum transportLineEnum = TransportLineEnum.codeOf(transportLine.getType());if (ObjectUtil.isEmpty(transportLineEnum)){throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR);}// 2.参数校验if (com.sl.transport.common.util.ObjectUtil.hasEmpty(transportLine.getStartOrganId(),transportLine.getEndOrganId())){throw new SLException(ExceptionEnum.START_END_ORGAN_NOT_FOUND);}// 3.判断起点和终点不能相同if (ObjectUtil.equals(transportLine.getStartOrganId(),transportLine.getEndOrganId())){throw new SLException(ExceptionEnum.TRANSPORT_LINE_ORGAN_CANNOT_SAME);}// 4.判断路线是否重复// 新增路线业务规则:干线:起点终点无顺序; 支线:起点必须是二级转运中心; 接驳路线:起点必须是网点BaseEntity firstNode;BaseEntity secondNode;switch (transportLineEnum){case TRUNK_LINE:// 干线:起点终点无顺序firstNode = OLTEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = OLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;case BRANCH_LINE:// 支线:起点必须是 二级转运中心firstNode = TLTEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = OLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;case CONNECT_LINE://  接驳路线:起点必须是 网点firstNode = AgencyEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = TLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;default:// 路线类型错误throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR);}// 查询数据节点之间的关系数量Long count = this.transportLineRepository.queryCount(firstNode, secondNode);if (count > 0){throw new SLException(ExceptionEnum.TRANSPORT_LINE_ALREADY_EXISTS);}// 5.创建路线,创建之前补充线路基本信息:距离、成本、时间等transportLine.setId(null);transportLine.setCreated(System.currentTimeMillis());transportLine.setUpdated(transportLine.getCreated());this.infoFromMap(firstNode,secondNode,transportLine);count = this.transportLineRepository.create(firstNode, secondNode, transportLine);return count > 0;}/*** 通过地图查询距离、时间,计算成本** @param firstNode     开始节点* @param secondNode    结束节点* @param transportLine 路线对象*/private void infoFromMap(BaseEntity firstNode, BaseEntity secondNode, TransportLine transportLine) {}

三十七、线路管理之新增路线(下)

1.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 新增路线** @param transportLine 路线数据* @return 是否成功*/@Overridepublic Boolean createLine(TransportLine transportLine) {// 创建路线,判断是否重复,判断起点终点是否相同,设置路线信息(成本、距离、时间)// 1.路线类型,类型必须符合要求的,不符合抛出异常TransportLineEnum transportLineEnum = TransportLineEnum.codeOf(transportLine.getType());if (ObjectUtil.isEmpty(transportLineEnum)){throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR);}// 2.参数校验if (com.sl.transport.common.util.ObjectUtil.hasEmpty(transportLine.getStartOrganId(),transportLine.getEndOrganId())){throw new SLException(ExceptionEnum.START_END_ORGAN_NOT_FOUND);}// 3.判断起点和终点不能相同if (ObjectUtil.equals(transportLine.getStartOrganId(),transportLine.getEndOrganId())){throw new SLException(ExceptionEnum.TRANSPORT_LINE_ORGAN_CANNOT_SAME);}// 4.判断路线是否重复// 新增路线业务规则:干线:起点终点无顺序; 支线:起点必须是二级转运中心; 接驳路线:起点必须是网点BaseEntity firstNode;BaseEntity secondNode;switch (transportLineEnum){case TRUNK_LINE:// 干线:起点终点无顺序firstNode = OLTEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = OLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;case BRANCH_LINE:// 支线:起点必须是 二级转运中心firstNode = TLTEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = OLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;case CONNECT_LINE://  接驳路线:起点必须是 网点firstNode = AgencyEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = TLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;default:// 路线类型错误throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR);}// 查询数据节点之间的关系数量Long count = this.transportLineRepository.queryCount(firstNode, secondNode);if (count > 0){throw new SLException(ExceptionEnum.TRANSPORT_LINE_ALREADY_EXISTS);}// 5.创建路线,创建之前补充线路基本信息:距离、成本、时间等transportLine.setId(null);transportLine.setCreated(System.currentTimeMillis());transportLine.setUpdated(transportLine.getCreated());this.infoFromMap(firstNode,secondNode,transportLine);count = this.transportLineRepository.create(firstNode, secondNode, transportLine);return count > 0;}/*** 通过地图查询距离、时间,计算成本** @param firstNode     开始节点* @param secondNode    结束节点* @param transportLine 路线对象*/private void infoFromMap(BaseEntity firstNode, BaseEntity secondNode, TransportLine transportLine) {// 查询两个节点之间的实际距离,需要借助于第三方地图服务商来查询,通过EagleMap查询高德的服务// 查询起点、终点的信息,主要获取经纬度数据OrganDTO originOrgan = this.organService.findByBid(firstNode.getBid());OrganDTO destinationOrgan = this.organService.findByBid(secondNode.getBid());// 校验坐标信息是否存在if (ObjectUtil.hasEmpty(originOrgan.getLongitude(),originOrgan.getLatitude(),destinationOrgan.getLongitude(),destinationOrgan.getLatitude())){throw new SLException(ExceptionEnum.ORGAN_LOCATION_INFO_NOT_EXISTS);}// 设置起点、终点坐标Coordinate origin = new Coordinate(originOrgan.getLongitude(),originOrgan.getLatitude());Coordinate destination = new Coordinate(destinationOrgan.getLongitude(),destinationOrgan.getLatitude());// 控制高德api返回时间参数,如果不设置,不会返回Map<String, Object> requestParam = MapUtil.<String, Object>builder("show_fields","cost").build();String driving = this.eagleMapTemplate.opsForDirection().driving(ProviderEnum.AMAP, origin, destination, requestParam);// 解析json数据JSONObject jsonObject = JSONUtil.parseObj(driving);// 获取距离,单位:米Double distance = jsonObject.getByPath("route.paths[0].distance", Double.class);transportLine.setDistance(distance);// 获取时间,单位:秒Long duration = jsonObject.getByPath("route.paths[0].cost.duration", Long.class);transportLine.setTime(duration);// 获取成本:单位:元// TODO 成本之后再实现transportLine.setCost(100d);}}

三十八、线路管理之查询路线数量

1.interface TransportLineRepository

package com.sl.transport.repository;/*** 查询数据节点之间的关系数量** @param firstNode  第一个节点* @param secondNode 第二个节点* @return 数量*/Long queryCount(BaseEntity firstNode, BaseEntity secondNode);

2.TransportLineRepositoryImpl.java

package com.sl.transport.repository.impl;/*** 查询数据节点之间的关系数量** @param firstNode  第一个节点* @param secondNode 第二个节点* @return 数量*/@Overridepublic Long queryCount(BaseEntity firstNode, BaseEntity secondNode) {// 1.获取@Node中的类型String firstNodeType = firstNode.getClass().getAnnotation(Node.class).value()[0];String secondNodeType = secondNode.getClass().getAnnotation(Node.class).value()[0];// 2.定义查询语句String cypherQuery = StrUtil.format("MATCH (m:{}) -[r]- (n:{}) \n" +"WHERE m.bid = $firstNodeBid AND n.bid = $secondNodeBid \n" +"RETURN count(r) AS c",firstNodeType,secondNodeType);// 3.执行查询并返回结果return this.neo4jClient.query(cypherQuery).bind(firstNode.getBid()).to("firstNodeBid").bind(secondNode.getBid()).to("secondNodeBid").fetchAs(Long.class).mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))).one().orElse(0L);}

三十九、线路管理之创建路线

1.TransportLineController.java

package com.sl.transport.controller;/*** 新增路线** @param transportLineDTO 路线数据* @return 是否成功*/@ApiOperation(value = "新增路线", notes = "新增路线,干线:起点终点无顺序,支线:起点必须是二级转运中心,接驳路线:起点必须是网点")@PostMappingpublic void createLine(@RequestBody TransportLineDTO transportLineDTO) {TransportLine transportLine = TransportLineUtils.toEntity(transportLineDTO);Boolean result = this.transportLineService.createLine(transportLine);if (!result) {throw new SLException("新增路线失败!", HttpStatus.INTERNAL_SERVER_ERROR.value());}}

2.interface TransportLineService

package com.sl.transport.service;/*** 新增路线** @param transportLine 路线数据* @return 是否成功*/Boolean createLine(TransportLine transportLine);

3.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 新增路线** @param transportLine 路线数据* @return 是否成功*/@Overridepublic Boolean createLine(TransportLine transportLine) {// 创建路线,判断是否重复,判断起点终点是否相同,设置路线信息(成本、距离、时间)// 1.路线类型,类型必须符合要求的,不符合抛出异常TransportLineEnum transportLineEnum = TransportLineEnum.codeOf(transportLine.getType());if (ObjectUtil.isEmpty(transportLineEnum)){throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR);}// 2.参数校验if (com.sl.transport.common.util.ObjectUtil.hasEmpty(transportLine.getStartOrganId(),transportLine.getEndOrganId())){throw new SLException(ExceptionEnum.START_END_ORGAN_NOT_FOUND);}// 3.判断起点和终点不能相同if (ObjectUtil.equals(transportLine.getStartOrganId(),transportLine.getEndOrganId())){throw new SLException(ExceptionEnum.TRANSPORT_LINE_ORGAN_CANNOT_SAME);}// 4.判断路线是否重复// 新增路线业务规则:干线:起点终点无顺序; 支线:起点必须是二级转运中心; 接驳路线:起点必须是网点BaseEntity firstNode;BaseEntity secondNode;switch (transportLineEnum){case TRUNK_LINE:// 干线:起点终点无顺序firstNode = OLTEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = OLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;case BRANCH_LINE:// 支线:起点必须是 二级转运中心firstNode = TLTEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = OLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;case CONNECT_LINE://  接驳路线:起点必须是 网点firstNode = AgencyEntity.builder().bid(transportLine.getStartOrganId()).build();secondNode = TLTEntity.builder().bid(transportLine.getEndOrganId()).build();break;default:// 路线类型错误throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR);}// 查询数据节点之间的关系数量Long count = this.transportLineRepository.queryCount(firstNode, secondNode);if (count > 0){throw new SLException(ExceptionEnum.TRANSPORT_LINE_ALREADY_EXISTS);}// 5.创建路线,创建之前补充线路基本信息:距离、成本、时间等transportLine.setId(null);transportLine.setCreated(System.currentTimeMillis());transportLine.setUpdated(transportLine.getCreated());this.infoFromMap(firstNode,secondNode,transportLine);count = this.transportLineRepository.create(firstNode, secondNode, transportLine);return count > 0;}

4.interface TransportLineRepository

package com.sl.transport.repository;/*** 查询数据节点之间的关系数量** @param firstNode  第一个节点* @param secondNode 第二个节点* @return 数量*/Long queryCount(BaseEntity firstNode, BaseEntity secondNode);

5.TransportLineRepositoryImpl.java

package com.sl.transport.repository.impl;/*** 查询数据节点之间的关系数量** @param firstNode  第一个节点* @param secondNode 第二个节点* @return 数量*/@Overridepublic Long queryCount(BaseEntity firstNode, BaseEntity secondNode) {// 1.获取@Node中的类型String firstNodeType = firstNode.getClass().getAnnotation(Node.class).value()[0];String secondNodeType = secondNode.getClass().getAnnotation(Node.class).value()[0];// 2.定义查询语句String cypherQuery = StrUtil.format("MATCH (m:{}) -[r]- (n:{}) \n" +"WHERE m.bid = $firstNodeBid AND n.bid = $secondNodeBid \n" +"RETURN count(r) AS c",firstNodeType,secondNodeType);// 3.执行查询并返回结果return this.neo4jClient.query(cypherQuery).bind(firstNode.getBid()).to("firstNodeBid").bind(secondNode.getBid()).to("secondNodeBid").fetchAs(Long.class).mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))).one().orElse(0L);}

6.interface TransportLineRepository

package com.sl.transport.repository;/*** 新增路线** @param firstNode     第一个节点* @param secondNode    第二个节点* @param transportLine 路线数据* @return 新增关系的数量*/Long create(BaseEntity firstNode, BaseEntity secondNode, TransportLine transportLine);

7.TransportLineRepositoryImpl.java

package com.sl.transport.repository.impl;/*** 新增路线** @param firstNode     第一个节点* @param secondNode    第二个节点* @param transportLine 路线数据* @return 新增关系的数量*/@Overridepublic Long create(BaseEntity firstNode, BaseEntity secondNode, TransportLine transportLine) {// 1.获取@Node中的类型String firstNodeType = firstNode.getClass().getAnnotation(Node.class).value()[0];String secondNodeType = secondNode.getClass().getAnnotation(Node.class).value()[0];// 2.定义查询语句String cypherQuery = StrUtil.format("MATCH (m:{})\n" +"WHERE m.bid = $firstNodeBid \n" +"MATCH (n:{})\n" +"WHERE n.bid = $secondNodeBid \n" +"CREATE\n" +"(m) -[r:IN_LINE {cost:$cost, number:$number, type:$type, name:$name, distance:$distance, time:$time, extra:$extra, startOrganId:$startOrganId, endOrganId:$endOrganId,created:$created, updated:$updated}]-> (n),\n" +"(m) <-[:OUT_LINE {cost:$cost, number:$number, type:$type, name:$name, distance:$distance, time:$time, extra:$extra, startOrganId:$startOrganId, endOrganId:$endOrganId,created:$created, updated:$updated}]- (n)\n" +"RETURN count(r) AS c",firstNodeType,secondNodeType);// 3.执行查询并返回结果return this.neo4jClient.query(cypherQuery).bind(firstNode.getBid()).to("firstNodeBid").bind(secondNode.getBid()).to("secondNodeBid").bindAll(BeanUtil.beanToMap(transportLine)).fetchAs(Long.class).mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))).one().orElse(0L);}

四十、线路管理之查询路线

1.TransportLineController.java

package com.sl.transport.controller;/*** 分页查询路线** @param transportLineSearchDTO 搜索参数* @return 路线列表*/@ApiOperation(value = "分页查询路线", notes = "分页查询路线,如果有条件就进行筛选查询")@PostMapping("page")public PageResponse<TransportLineDTO> queryPageList(@RequestBody TransportLineSearchDTO transportLineSearchDTO) {PageResponse<TransportLine> pageResponse = this.transportLineService.queryPageList(transportLineSearchDTO);PageResponse<TransportLineDTO> result = new PageResponse<>();BeanUtil.copyProperties(pageResponse, result, "items");result.setItems(TransportLineUtils.toDTOList(pageResponse.getItems()));return result;}

2.interface TransportLineService

package com.sl.transport.service;/*** 分页查询路线** @param transportLineSearchDTO 搜索参数* @return 路线列表*/PageResponse<TransportLine> queryPageList(TransportLineSearchDTO transportLineSearchDTO);

3.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 分页查询路线** @param transportLineSearchDTO 搜索参数* @return 路线列表*/@Overridepublic PageResponse<TransportLine> queryPageList(TransportLineSearchDTO transportLineSearchDTO) {return this.transportLineRepository.queryPageList(transportLineSearchDTO);}

4.interface TransportLineRepository

package com.sl.transport.repository;/*** 分页查询路线** @param transportLineSearchDTO 搜索参数* @return 路线列表*/PageResponse<TransportLine> queryPageList(TransportLineSearchDTO transportLineSearchDTO);

5.TransportLineRepositoryImpl.java

package com.sl.transport.repository.impl;/*** 分页查询路线** @param transportLineSearchDTO 搜索参数* @return 路线列表*/@Overridepublic PageResponse<TransportLine> queryPageList(TransportLineSearchDTO transportLineSearchDTO) {// 1.获取分页参数Integer page = Math.max(transportLineSearchDTO.getPage(),1);Integer pageSize = transportLineSearchDTO.getPageSize();Integer skip = (page - 1) * pageSize;// 2.构造生成查询语句Map<String, Object> searchParam = BeanUtil.beanToMap(transportLineSearchDTO,false,true);MapUtil.removeAny(searchParam,"page","pageSize");String[] cypher = this.buildPageQueryCypher(searchParam);// 3.查询数据ArrayList<TransportLine> transportLineList = ListUtil.toList(this.neo4jClient.query(cypher[0]).bind(skip).to("skip").bind(pageSize).to("limit").bindAll(cn.hutool.core.bean.BeanUtil.beanToMap(transportLineSearchDTO, false, true)).fetchAs(TransportLine.class).mappedBy((typeSystem, record) -> this.toTransportLine(record)).all());// 4.查询数量Long count = this.neo4jClient.query(cypher[1]).bindAll(cn.hutool.core.bean.BeanUtil.beanToMap(transportLineSearchDTO, false, true)).fetchAs(Long.class).mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))).one().orElse(0L);// 计算总页数int pages = PageUtil.totalPage(count.intValue(), pageSize);return PageResponse.of(transportLineList,page,pageSize,Convert.toLong(pages),count);}/*** 通过搜索条件构造查询语句* @param searchParam 搜索条件* @return 数组,长度为2,第一个是查询内容语句,第二个是查询数量的语句*/private String[] buildPageQueryCypher(Map<String, Object> searchParam) {String cypherQuery;String cypherCountQuery;if (ObjectUtil.isEmpty(searchParam)){// 无搜索条件cypherQuery = "MATCH (m) -[r]-> (n) RETURN m,r,n ORDER BY id(r) DESC SKIP $skip LIMIT $limit";cypherCountQuery = "MATCH () -[r]-> () RETURN count(r) AS c";}else {// 有搜索条件String cypherPrefix = "MATCH (m) -[r]-> (n)";StringBuilder sb = new StringBuilder();sb.append(cypherPrefix).append(" WHERE 1=1 ");for (String key : searchParam.keySet()) {Object value = searchParam.get(key);if (value instanceof String) {sb.append(StrUtil.format(" AND r.{} CONTAINS '{}' ", key, value.toString()));} else {sb.append(StrUtil.format(" AND r.{} = ${} ", key, key));}}String cypher = sb.toString();cypherQuery = cypher + " RETURN m,r,n ORDER BY id(r) DESC SKIP $skip LIMIT $limit";cypherCountQuery = cypher + " RETURN count(r) AS c";}return new String[]{cypherQuery,cypherCountQuery};}/*** 将Neo4j查询结果记录转换为TransportLine对象* @param record Neo4j查询结果记录* @return TransportLine对象*/private TransportLine toTransportLine(Record record) {org.neo4j.driver.types.Node startNode = record.get("m").asNode();org.neo4j.driver.types.Node endNode = record.get("n").asNode();Relationship relationship = record.get("r").asRelationship();Map<String, Object> map = relationship.asMap();TransportLine transportLine = BeanUtil.toBeanIgnoreError(map, TransportLine.class);transportLine.setStartOrganName(startNode.get("name").asString());transportLine.setStartOrganId(startNode.get("bid").asLong());transportLine.setEndOrganName(endNode.get("name").asString());transportLine.setEndOrganId(endNode.get("bid").asLong());transportLine.setId(relationship.id());return transportLine;}

四十一、线路成本

1.CostConfigurationController.java

package com.sl.transport.controller;/*** 成本配置相关业务对外提供接口服务*/
@Api(tags = "成本配置")
@RequestMapping("cost-configuration")
@Validated
@RestController
public class CostConfigurationController {@Resourceprivate CostConfigurationService costConfigurationService;/*** 查询成本配置** @return 成本配置列表*/@ApiOperation(value = "查询成本配置")@GetMappingpublic List<CostConfigurationDTO> findConfiguration() {return costConfigurationService.findConfiguration();}/*** 保存成本配置** @param dto 成本配置列表*/@ApiOperation(value = "保存成本配置")@PostMappingpublic void saveConfiguration(@RequestBody List<CostConfigurationDTO> dto) {costConfigurationService.saveConfiguration(dto);}}

2.interface CostConfigurationService

package com.sl.transport.service;/*** 成本配置相关业务*/
public interface CostConfigurationService {/*** 查询成本配置** @return 成本配置*/List<CostConfigurationDTO> findConfiguration();/*** 保存成本配置* @param dto 成本配置*/void saveConfiguration(List<CostConfigurationDTO> dto);/*** 查询成本根据类型* @param type 类型* @return 成本*/Double findCostByType(Integer type);
}

3.CostConfigurationServiceImpl.java

package com.sl.transport.service.impl;/*** 成本配置相关业务*/
@Service
public class CostConfigurationServiceImpl implements CostConfigurationService {/*** 成本配置 redis key*/private static final String key = "SL_TRANSPORT_COST_CONFIGURATION";/*** 默认成本配置*/private static final Map<Object, Object> DEFAULT_COST = Map.of(TransportLineEnum.TRUNK_LINE.getCode(), 0.8,TransportLineEnum.BRANCH_LINE.getCode(), 1.2,TransportLineEnum.CONNECT_LINE.getCode(), 1.5);@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** 查询成本配置** @return 成本配置列表*/@Overridepublic List<CostConfigurationDTO> findConfiguration() {Map<Object, Object> entries = this.stringRedisTemplate.opsForHash().entries(key);if (ObjectUtil.isEmpty(entries)){// 使用默认值entries = DEFAULT_COST;}// 返回return entries.entrySet().stream().map(v -> new CostConfigurationDTO(Convert.toInt(v.getKey()),Convert.toDouble(v.getValue()))).collect(Collectors.toList());}/*** 保存成本配置* @param dto 成本配置*/@Overridepublic void saveConfiguration(List<CostConfigurationDTO> dto) {Map<String, String> map = dto.stream().collect(Collectors.toMap(v -> v.getTransportLineType().toString(), v -> v.getCost().toString()));this.stringRedisTemplate.opsForHash().putAll(key,map);}/*** 查询成本根据类型* @param type 类型* @return 成本*/@Overridepublic Double findCostByType(Integer type) {if (ObjectUtil.isEmpty(type)) {throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR);}// 查询redisObject o = this.stringRedisTemplate.opsForHash().get(key, type.toString());if (ObjectUtil.isNotEmpty(o)){return Convert.toDouble(o);}// 返回默认值return Convert.toDouble(DEFAULT_COST.get(type));}
}

4.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 通过地图查询距离、时间,计算成本** @param firstNode     开始节点* @param secondNode    结束节点* @param transportLine 路线对象*/private void infoFromMap(BaseEntity firstNode, BaseEntity secondNode, TransportLine transportLine) {// 查询两个节点之间的实际距离,需要借助于第三方地图服务商来查询,通过EagleMap查询高德的服务// 查询起点、终点的信息,主要获取经纬度数据OrganDTO originOrgan = this.organService.findByBid(firstNode.getBid());OrganDTO destinationOrgan = this.organService.findByBid(secondNode.getBid());// 校验坐标信息是否存在if (ObjectUtil.hasEmpty(originOrgan.getLongitude(),originOrgan.getLatitude(),destinationOrgan.getLongitude(),destinationOrgan.getLatitude())){throw new SLException(ExceptionEnum.ORGAN_LOCATION_INFO_NOT_EXISTS);}// 设置起点、终点坐标Coordinate origin = new Coordinate(originOrgan.getLongitude(),originOrgan.getLatitude());Coordinate destination = new Coordinate(destinationOrgan.getLongitude(),destinationOrgan.getLatitude());// 控制高德api返回时间参数,如果不设置,不会返回Map<String, Object> requestParam = MapUtil.<String, Object>builder("show_fields","cost").build();String driving = this.eagleMapTemplate.opsForDirection().driving(ProviderEnum.AMAP, origin, destination, requestParam);// 解析json数据JSONObject jsonObject = JSONUtil.parseObj(driving);// 获取距离,单位:米Double distance = jsonObject.getByPath("route.paths[0].distance", Double.class);transportLine.setDistance(distance);// 获取时间,单位:秒Long duration = jsonObject.getByPath("route.paths[0].cost.duration", Long.class);transportLine.setTime(duration);// 获取成本:单位:元// TODO 成本已实现Double cost = this.costConfigurationService.findCostByType(transportLine.getType());double div = NumberUtil.div(distance, Convert.toDouble(1000), 0);transportLine.setCost(NumberUtil.mul(cost,Convert.toDouble(div)));}

四十二、调度策略规划路线

1.DispatchConfigurationController.java

package com.sl.transport.controller;/*** 调度配置相关业务对外提供接口服务** @author zzj* @version 1.0*/
@Api(tags = "调度配置")
@RequestMapping("dispatch-configuration")
@Validated
@RestController
public class DispatchConfigurationController {@Resourceprivate DispatchConfigurationService dispatchConfigurationService;@ApiOperation(value = "查询调度配置")@GetMappingpublic DispatchConfigurationDTO findConfiguration() {return dispatchConfigurationService.findConfiguration();}@ApiOperation(value = "保存调度配置")@PostMappingpublic void saveConfiguration(@RequestBody DispatchConfigurationDTO dto) {dispatchConfigurationService.saveConfiguration(dto);}
}

2.interface DispatchConfigurationService

package com.sl.transport.service;/*** 调度配置相关业务** @author zzj* @version 1.0*/
public interface DispatchConfigurationService {/*** 查询调度配置** @return 调度配置*/DispatchConfigurationDTO findConfiguration();/*** 保存调度配置* @param dto 调度配置*/void saveConfiguration(DispatchConfigurationDTO dto);
}

3.DispatchConfigurationServiceImpl.java

package com.sl.transport.service.impl;@Service
public class DispatchConfigurationServiceImpl implements DispatchConfigurationService {@Resourceprivate StringRedisTemplate stringRedisTemplate;/*** 调度时间配置*/static final String timeKey = "DISPATCH_CONFIGURATION:TIME";/*** 调度方式配置*/static final String methodKey = "DISPATCH_CONFIGURATION:METHOD";/*** 查询调度配置** @return 调度配置*/@Overridepublic DispatchConfigurationDTO findConfiguration() {// 调度时间配置String dispatchTime = this.stringRedisTemplate.opsForValue().get(timeKey);// 调度方式配置String dispatchMethod = this.stringRedisTemplate.opsForValue().get(methodKey);// 组装响应结果return DispatchConfigurationDTO.builder()// 如果查不到调度时间,默认值为2小时.dispatchTime(Convert.toInt(ObjectUtil.defaultIfBlank(dispatchTime,"2")))// 如果查不到调度方式,默认值为2成本最低.dispatchMethod(Convert.toInt(ObjectUtil.defaultIfBlank(dispatchMethod,"2"))).build();}/*** 保存调度配置* @param dto 调度配置*/@Overridepublic void saveConfiguration(DispatchConfigurationDTO dto) {if (ObjectUtil.isEmpty(dto)){throw new SLException(ExceptionEnum.DISPATCHTIME_AND_DISPATCHMETHOD_IS_NULL);}//调度时间配置this.stringRedisTemplate.opsForValue().set(timeKey,dto.getDispatchTime().toString());//调度方式配置this.stringRedisTemplate.opsForValue().set(methodKey,dto.getDispatchMethod().toString());}}

4.TransportLineServiceImpl.java

在这里调用到了这个方法

package com.sl.transport.service.impl;/*** 根据调度策略查询路线** @param startId 开始网点id* @param endId   结束网点id* @return 路线*/@Overridepublic TransportLineNodeDTO queryPathByDispatchMethod(Long startId, Long endId) {// 调度方式配置DispatchConfigurationDTO configuration = this.dispatchConfigurationService.findConfiguration();int dispatchMethod = configuration.getDispatchMethod();// 调度方式,1:转运次数最少; 2:成本最低if (ObjectUtil.equals(DispatchMethodEnum.SHORTEST_PATH.getCode(),dispatchMethod)){return this.queryShortestPath(startId,endId);}else {return this.findLowestPath(startId,endId);}}

四十三、课堂练习-删除路线

1.TransportLineController.java

package com.sl.transport.controller;/*** 删除路线** @param id 路线id* @return 是否成功*/@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "路线id", required = true)})@ApiOperation(value = "删除路线", notes = "删除路线,单向删除")@DeleteMapping("{id}")public void deleteLine(@PathVariable("id") Long id) {Boolean result = this.transportLineService.deleteLine(id);if (!result) {throw new SLException("更新路线失败!", HttpStatus.INTERNAL_SERVER_ERROR.value());}}

2.interface TransportLineService

package com.sl.transport.service;/*** 删除路线** @param id 路线id* @return 是否成功*/Boolean deleteLine(Long id);

3.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 删除路线** @param id 路线id* @return 是否成功*/@Overridepublic Boolean deleteLine(Long id) {Long count = this.transportLineRepository.remove(id);return count > 0;}

4.interface TransportLineRepository

package com.sl.transport.repository;/*** 删除路线** @param lineId 关系id* @return 删除关系的数量*/Long remove(Long lineId);

5.TransportLineRepositoryImpl.java

package com.sl.transport.repository.impl;/*** 删除路线** @param lineId 关系id* @return 删除关系的数量*/@Overridepublic Long remove(Long lineId) {// 1. 定义查询语句:只删除关系String cypherQuery = "MATCH ()-[r]->() WHERE id(r) = $id DELETE r";// 2. 执行查询并返回结果var result = this.neo4jClient.query(cypherQuery).bind(lineId).to("id") // 绑定参数 lineId 到查询中的 id.run(); // 执行查询// 3. 获取删除的关系数量int count = result.counters().relationshipsDeleted(); // 获取删除的关系数量return Convert.toLong(count); // 返回删除的关系数量,转为 Long 类型}

四十四、课堂练习-根据id和ids查询路线

1.TransportLineController.java

package com.sl.transport.controller;/*** 根据id查询路线** @param id 路线id* @return 路线数据*/@ApiImplicitParams({@ApiImplicitParam(name = "id", value = "路线id", required = true)})@ApiOperation(value = "根据id查询路线", notes = "根据id查询路线")@GetMapping("{id}")public TransportLineDTO queryById(@PathVariable("id") Long id) {TransportLine transportLine = this.transportLineService.queryById(id);return TransportLineUtils.toDTO(transportLine);}/*** 根据ids批量查询路线** @param ids id列表* @return 路线列表*/@ApiImplicitParams({@ApiImplicitParam(name = "ids", value = "路线id列表", required = true)})@ApiOperation(value = "根据ids批量查询路线", notes = "根据ids批量查询路线")@GetMapping("list")public List<TransportLineDTO> queryByIds(@Size(min = 1, message = "至少要传入1个id") @RequestParam("ids") Long[] ids) {List<TransportLine> list = this.transportLineService.queryByIds(ids);return TransportLineUtils.toDTOList(list);}

2.interface TransportLineService

package com.sl.transport.service;/*** 根据ids批量查询路线** @param ids id列表* @return 路线列表*/List<TransportLine> queryByIds(Long... ids);/*** 根据id查询路线** @param id 路线id* @return 路线数据*/TransportLine queryById(Long id);

3.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 根据ids批量查询路线** @param ids id列表* @return 路线列表*/@Overridepublic List<TransportLine> queryByIds(Long... ids) {return this.transportLineRepository.queryByIds(ids);}/*** 根据id查询路线** @param id 路线id* @return 路线数据*/@Overridepublic TransportLine queryById(Long id) {return this.transportLineRepository.queryById(id);}

4.interface TransportLineRepository

package com.sl.transport.repository;/*** 根据ids批量查询路线** @param ids id列表* @return 路线列表*/List<TransportLine> queryByIds(Long... ids);/*** 根据id查询路线** @param id 路线id* @return 路线数据*/TransportLine queryById(Long id);

5.TransportLineRepositoryImpl.java

package com.sl.transport.repository.impl;/*** 根据ids批量查询路线** @param ids id列表* @return 路线列表*/@Overridepublic List<TransportLine> queryByIds(Long... ids) {// 1. 定义查询语句String cypherQuery = "MATCH (m) -[r]-> (n)\n" +"WHERE id(r) in $ids\n" +"RETURN m,r,n";// 2. 执行查询并返回结果return ListUtil.toList(this.neo4jClient.query(cypherQuery).bind(ids).to("ids").fetchAs(TransportLine.class).mappedBy((typeSystem, record) -> {//封装数据return this.toTransportLine(record);}).all());}/*** 根据id查询路线** @param id 路线id* @return 路线数据*/@Overridepublic TransportLine queryById(Long id) {// 调用批量查询方法,传入单个idList<TransportLine> transportLines = this.queryByIds(id);// 判断查询结果是否为空,如果不为空则返回第一条记录if (ObjectUtil.isNotEmpty(transportLines)) {return transportLines.get(0);}// 如果查询结果为空,则返回nullreturn null;}

四十五、课堂练习-更新路线

1.TransportLineController.java

package com.sl.transport.controller;/*** 更新路线** @param transportLineDTO 路线数据* @return 是否成功*/@ApiOperation(value = "更新路线", notes = "更新路线,可更新字段:cost、name、distance、time、extra,更新数据时id不能为空")@PutMappingpublic void updateLine(@RequestBody TransportLineDTO transportLineDTO) {TransportLine transportLine = TransportLineUtils.toEntity(transportLineDTO);Boolean result = this.transportLineService.updateLine(transportLine);if (!result) {throw new SLException("更新路线失败!", HttpStatus.INTERNAL_SERVER_ERROR.value());}}

2.interface TransportLineService

package com.sl.transport.service;/*** 更新路线** @param transportLine 路线数据* @return 是否成功*/Boolean updateLine(TransportLine transportLine);

3.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 更新路线** @param transportLine 路线数据* @return 是否成功*/@Overridepublic Boolean updateLine(TransportLine transportLine) {Long count = this.transportLineRepository.update(transportLine);return count > 0;}

4.interface TransportLineRepository

package com.sl.transport.repository;/*** 更新路线** @param transportLine 路线数据* @return 更新的数量*/Long update(TransportLine transportLine);

5.TransportLineRepositoryImpl.java

package com.sl.transport.repository.impl;/*** 更新路线** @param transportLine 路线数据* @return 更新的数量*/@Overridepublic Long update(TransportLine transportLine) {// 1. 定义查询语句String cypherQuery = "MATCH () -[r]-> ()\n" +"WHERE id(r) = $id\n" +"SET r.cost = $cost , r.number = $number, r.name = $name ,r.distance = $distance ,r.time = $time, r.startOrganId = $startOrganId, r.endOrganId = $endOrganId, r.updated = $updated , r.extra = $extra \n" +"RETURN count(r) AS c";// 2. 执行查询并返回结果Optional<Long> optional = this.neo4jClient.query(cypherQuery).bindAll(BeanUtil.beanToMap(transportLine)).fetchAs(Long.class).mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))).one();return optional.orElse(0L);}

四十六、课堂练习-转运节点优先规划+成本优先规划

1.TransportLineController.java

package com.sl.transport.controller;/*** 查询两个网点之间最短的路线,最大查询深度为:10** @param startId 开始网点id* @param endId   结束网点id* @return 路线*/@ApiImplicitParams({@ApiImplicitParam(name = "startId", value = "开始网点业务id", required = true),@ApiImplicitParam(name = "endId", value = "结束网点业务id", required = true)})@ApiOperation(value = "最短的路线", notes = "查询两个网点之间最短的路线,最大查询深度为:10")@GetMapping("{startId}/{endId}")public TransportLineNodeDTO queryShortestPath(@NotNull(message = "startId不能为空") @PathVariable("startId") Long startId,@NotNull(message = "endId不能为空") @PathVariable("endId") Long endId) {return this.transportLineService.queryShortestPath(startId, endId);}/*** 查询两个网点之间成本最低的路线,最大查询深度为:10** @param startId 开始网点id* @param endId   结束网点id* @return 路线集合*/@ApiImplicitParams({@ApiImplicitParam(name = "startId", value = "开始网点业务id", required = true),@ApiImplicitParam(name = "endId", value = "结束网点业务id", required = true)})@ApiOperation(value = "成本最低的路线", notes = "查询两个网点之间成本最低的路线,最大查询深度为:10")@GetMapping("lowest/{startId}/{endId}")public TransportLineNodeDTO findLowestPath(@NotNull(message = "startId不能为空") @PathVariable("startId") Long startId,@NotNull(message = "endId不能为空") @PathVariable("endId") Long endId) {return this.transportLineService.findLowestPath(startId, endId);}/*** 根据调度策略查询路线** @param startId 开始网点id* @param endId   结束网点id* @return 路线*/@ApiImplicitParams({@ApiImplicitParam(name = "startId", value = "开始网点业务id", required = true),@ApiImplicitParam(name = "endId", value = "结束网点业务id", required = true)})@ApiOperation(value = "根据调度策略查询路线", notes = "根据调度策略选择最短路线或者成本最低路线")@GetMapping("/dispatchMethod/{startId}/{endId}")public TransportLineNodeDTO queryPathByDispatchMethod(@NotNull(message = "startId不能为空") @PathVariable("startId") Long startId,@NotNull(message = "endId不能为空") @PathVariable("endId") Long endId) {return this.transportLineService.queryPathByDispatchMethod(startId, endId);}

2.interface TransportLineService

package com.sl.transport.service;/*** 查询两个网点之间最短的路线,最大查询深度为:10** @param startId 开始网点id* @param endId   结束网点id* @return 路线*/TransportLineNodeDTO queryShortestPath(Long startId, Long endId);/*** 查询两个网点之间成本最低的路线,最大查询深度为:10** @param startId 开始网点id* @param endId   结束网点id* @return 路线集合*/TransportLineNodeDTO findLowestPath(Long startId, Long endId);/*** 根据调度策略查询路线** @param startId 开始网点id* @param endId   结束网点id* @return 路线*/TransportLineNodeDTO queryPathByDispatchMethod(Long startId, Long endId);

3.TransportLineServiceImpl.java

package com.sl.transport.service.impl;/*** 查询两个网点之间最短的路线,最大查询深度为:10** @param startId 开始网点id* @param endId   结束网点id* @return 路线*/@Overridepublic TransportLineNodeDTO queryShortestPath(Long startId, Long endId) {AgencyEntity start = AgencyEntity.builder().bid(startId).build();AgencyEntity end = AgencyEntity.builder().bid(endId).build();if (ObjectUtil.hasEmpty(start,end)){throw new SLException(ExceptionEnum.START_END_ORGAN_NOT_FOUND);}return this.transportLineRepository.findShortestPath(start,end);}/*** 查询两个网点之间成本最低的路线,最大查询深度为:10** @param startId 开始网点id* @param endId   结束网点id* @return 路线集合*/@Overridepublic TransportLineNodeDTO findLowestPath(Long startId, Long endId) {AgencyEntity start = AgencyEntity.builder().bid(startId).build();AgencyEntity end = AgencyEntity.builder().bid(endId).build();if (ObjectUtil.hasEmpty(start, end)) {throw new SLException(ExceptionEnum.START_END_ORGAN_NOT_FOUND);}List<TransportLineNodeDTO> pathList = this.transportLineRepository.findPathList(start, end, 10, 1);if (CollUtil.isNotEmpty(pathList)) {return pathList.get(0);}return null;}/*** 根据调度策略查询路线** @param startId 开始网点id* @param endId   结束网点id* @return 路线*/@Overridepublic TransportLineNodeDTO queryPathByDispatchMethod(Long startId, Long endId) {// 调度方式配置DispatchConfigurationDTO configuration = this.dispatchConfigurationService.findConfiguration();int dispatchMethod = configuration.getDispatchMethod();// 调度方式,1:转运次数最少; 2:成本最低if (ObjectUtil.equals(DispatchMethodEnum.SHORTEST_PATH.getCode(),dispatchMethod)){return this.queryShortestPath(startId,endId);}else {return this.findLowestPath(startId,endId);}}

4.interface TransportLineRepository

package com.sl.transport.repository;/*** 查询两个网点之间最短的路线,查询深度为:10** @param start 开始网点* @param end   结束网点* @return 路线*/TransportLineNodeDTO findShortestPath(AgencyEntity start, AgencyEntity end);/*** 查询两个网点之间最短的路线,最大查询深度为:10** @param start 开始网点* @param end   结束网点* @param depth 查询深度,最大为:10* @return 路线*/TransportLineNodeDTO findShortestPath(AgencyEntity start, AgencyEntity end, int depth);/*** 查询两个网点之间的路线列表,成本优先 > 转运节点优先** @param start 开始网点* @param end   结束网点* @param depth 查询深度* @param limit 返回路线的数量* @return 路线*/List<TransportLineNodeDTO> findPathList(AgencyEntity start, AgencyEntity end, int depth, int limit);

5.TransportLineRepositoryImpl.java

package com.sl.transport.repository.impl;/*** 查询两个网点之间最短的路线,查询深度为:10** @param start 开始网点* @param end   结束网点* @return 路线*/@Overridepublic TransportLineNodeDTO findShortestPath(AgencyEntity start, AgencyEntity end) {return this.findShortestPath(start,end,10);}/*** 查询两个网点之间最短的路线,最大查询深度为:10** @param start 开始网点* @param end   结束网点* @param depth 查询深度,最大为:10* @return 路线*/@Overridepublic TransportLineNodeDTO findShortestPath(AgencyEntity start, AgencyEntity end, int depth) {//获取网点数据在Neo4j中的类型String type = AgencyEntity.class.getAnnotation(Node.class).value()[0];//构造查询语句String cypherQuery = StrUtil.format("MATCH path = shortestPath((start:{}) -[*..{}]-> (end:{}))\n" +"WHERE start.bid = $startId AND end.bid = $endId AND start.status = true AND end.status = true\n" +"RETURN path", type, depth, type);Collection<TransportLineNodeDTO> transportLineNodeDTOS = this.executeQueryPath(cypherQuery, start, end);if (CollUtil.isEmpty(transportLineNodeDTOS)) {return null;}for (TransportLineNodeDTO transportLineNodeDTO : transportLineNodeDTOS) {return transportLineNodeDTO;}return null;}/*** 执行路径查询语句,将查询结果转换为TransportLineNodeDTO对象集合** @param cypherQuery 查询语句* @param start       起始网点实体* @param end         终点网点实体* @return TransportLineNodeDTO对象列表*/private List<TransportLineNodeDTO> executeQueryPath(String cypherQuery, AgencyEntity start, AgencyEntity end) {return ListUtil.toList(this.neo4jClient.query(cypherQuery).bind(start.getBid()).to("startId") //设置参数.bind(end.getBid()).to("endId") //设置参数.fetchAs(TransportLineNodeDTO.class) //设置响应的类型.mappedBy((typeSystem, record) -> { //对结果进行封装处理PathValue pathValue = (PathValue) record.get(0);return TransportLineUtils.convert(pathValue);}).all());}/*** 查询两个网点之间的路线列表,成本优先 > 转运节点优先** @param start 开始网点* @param end   结束网点* @param depth 查询深度* @param limit 返回路线的数量* @return 路线*/@Overridepublic List<TransportLineNodeDTO> findPathList(AgencyEntity start, AgencyEntity end, int depth, int limit) {//获取网点数据在Neo4j中的类型String type = AgencyEntity.class.getAnnotation(Node.class).value()[0];//构造查询语句String cypherQuery = StrUtil.format("MATCH path = (start:{}) -[*..{}]-> (end:{})\n" +"WHERE start.bid = $startId AND end.bid = $endId AND start.status = true AND end.status = true\n" +"UNWIND relationships(path) AS r\n" +"WITH sum(r.cost) AS cost, path\n" +"RETURN path ORDER BY cost ASC, LENGTH(path) ASC LIMIT {}", type, depth, type, limit);return this.executeQueryPath(cypherQuery, start, end);}
http://www.dtcms.com/a/528136.html

相关文章:

  • 使用Ansys Polyflow对泡沫聚合物挤出进行建模
  • 【组成原理·硬件】6总线
  • Spring Boot3零基础教程,整合 SSM,笔记52
  • 序列化详解
  • 网站设计制作电影福建网站建设公司
  • 记录一次Oracle日志listener.log文件大小超过4G后出现Tomcat服务启动一直报错的原因【ORACLE】
  • Docker Desktop快速搭建本地k8s集群
  • LabVIEW超高分辨显微成像系统
  • 东莞建网站的公破解付费wordpress主题
  • 国产数据库破局:金仓数据库如何无缝替代MongoDB支撑2TB政务数据
  • Switch 20.5.0系统最新PSP模拟器懒人包
  • 怎么做网上直营店网站php素材网站源码免费下载
  • 巡检机器人户外视觉识别困境剖析与自动优化模式构建
  • C++ - 异常
  • C++笔记(面向对象)深赋值 浅赋值
  • 数据库在什么情况下会发生数据库死锁
  • 如何将Word文档精确转换为图片型PDF?
  • Auto CAD二次开发——封装事务处理函数并绘制直线函数
  • C4D域力场重要概念之点对象、粒子对象和通道转换
  • 车载诊断架构 ---关于Service 29证书认证与整车时间同步的问题带来的深思
  • 做蛋糕需要建议网站不wordpress跳转移动端模板
  • html5培训网站模板兴国电商网站建设
  • 【JUnit实战3_13】第八章:mock 对象模拟技术在细粒度测试中的应用(上)
  • STM32项目分享:简易自动门设计
  • 小白怎样建设公司网站奔奔网站建设
  • YouTube评论情感分析项目84%正确率:基于BERT的实战复现与原理解析
  • 【Shell】Shell变量
  • 华为OD机考:计算正方形数量(Python C/C++ JAVA JS GO)
  • 基于 STM32 的语音识别智能垃圾桶设计与实现
  • 【基础复习3】决策树