Commit 59c1b1517668e6c78d8eaaaca7c172e1dbd66bc5
1 parent
30db74bf
day06-路线规划之微服务
Showing
16 changed files
with
839 additions
and
15 deletions
.gitignore
.idea/compiler.xml
| @@ -141,6 +141,8 @@ | @@ -141,6 +141,8 @@ | ||
| 141 | <entry name="$MAVEN_REPOSITORY$/org/jsoup/jsoup/1.12.1/jsoup-1.12.1.jar" /> | 141 | <entry name="$MAVEN_REPOSITORY$/org/jsoup/jsoup/1.12.1/jsoup-1.12.1.jar" /> |
| 142 | <entry name="$MAVEN_REPOSITORY$/com/github/javaparser/javaparser-core/3.14.10/javaparser-core-3.14.10.jar" /> | 142 | <entry name="$MAVEN_REPOSITORY$/com/github/javaparser/javaparser-core/3.14.10/javaparser-core-3.14.10.jar" /> |
| 143 | <entry name="$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-databind/2.10.3/jackson-databind-2.10.3.jar" /> | 143 | <entry name="$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-databind/2.10.3/jackson-databind-2.10.3.jar" /> |
| 144 | + <entry name="$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-annotations/2.10.3/jackson-annotations-2.10.3.jar" /> | ||
| 145 | + <entry name="$MAVEN_REPOSITORY$/com/fasterxml/jackson/core/jackson-core/2.10.3/jackson-core-2.10.3.jar" /> | ||
| 144 | <entry name="$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter/5.6.2/junit-jupiter-5.6.2.jar" /> | 146 | <entry name="$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter/5.6.2/junit-jupiter-5.6.2.jar" /> |
| 145 | <entry name="$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.6.2/junit-jupiter-api-5.6.2.jar" /> | 147 | <entry name="$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.6.2/junit-jupiter-api-5.6.2.jar" /> |
| 146 | <entry name="$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar" /> | 148 | <entry name="$MAVEN_REPOSITORY$/org/apiguardian/apiguardian-api/1.1.0/apiguardian-api-1.1.0.jar" /> |
.idea/encodings.xml
| @@ -64,6 +64,8 @@ | @@ -64,6 +64,8 @@ | ||
| 64 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-core/src/main/java" charset="UTF-8" /> | 64 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-core/src/main/java" charset="UTF-8" /> |
| 65 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-core/src/main/resources" charset="UTF-8" /> | 65 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-core/src/main/resources" charset="UTF-8" /> |
| 66 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-dashboard/src/main/java" charset="UTF-8" /> | 66 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-dashboard/src/main/java" charset="UTF-8" /> |
| 67 | + <file url="file://$PROJECT_DIR$/sentinel/sentinel-dashboard/src/main/resources" charset="UTF-8" /> | ||
| 68 | + <file url="file://$PROJECT_DIR$/sentinel/sentinel-dashboard/src/main/webapp" charset="UTF-8" /> | ||
| 67 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-demo/sentinel-demo-annotation-cdi-interceptor/src/main/java" charset="UTF-8" /> | 69 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-demo/sentinel-demo-annotation-cdi-interceptor/src/main/java" charset="UTF-8" /> |
| 68 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-demo/sentinel-demo-annotation-cdi-interceptor/src/main/resources" charset="UTF-8" /> | 70 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-demo/sentinel-demo-annotation-cdi-interceptor/src/main/resources" charset="UTF-8" /> |
| 69 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java" charset="UTF-8" /> | 71 | <file url="file://$PROJECT_DIR$/sentinel/sentinel-demo/sentinel-demo-annotation-spring-aop/src/main/java" charset="UTF-8" /> |
.idea/sl-express.iml
| @@ -2,7 +2,10 @@ | @@ -2,7 +2,10 @@ | ||
| 2 | <module type="JAVA_MODULE" version="4"> | 2 | <module type="JAVA_MODULE" version="4"> |
| 3 | <component name="NewModuleRootManager" inherit-compiler-output="true"> | 3 | <component name="NewModuleRootManager" inherit-compiler-output="true"> |
| 4 | <exclude-output /> | 4 | <exclude-output /> |
| 5 | - <content url="file://$MODULE_DIR$" /> | 5 | + <content url="file://$MODULE_DIR$"> |
| 6 | + <excludeFolder url="file://$MODULE_DIR$/.idea/codeStyles" /> | ||
| 7 | + <excludeFolder url="file://$MODULE_DIR$/.idea/inspectionProfiles" /> | ||
| 8 | + </content> | ||
| 6 | <orderEntry type="inheritedJdk" /> | 9 | <orderEntry type="inheritedJdk" /> |
| 7 | <orderEntry type="sourceFolder" forTests="false" /> | 10 | <orderEntry type="sourceFolder" forTests="false" /> |
| 8 | </component> | 11 | </component> |
03-资料/maven/settings.xml
| @@ -4,10 +4,10 @@ | @@ -4,10 +4,10 @@ | ||
| 4 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | 4 | xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" |
| 5 | xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> | 5 | xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd"> |
| 6 | 6 | ||
| 7 | - <!-- 本地仓库 --> | ||
| 8 | - <localRepository>F:\maven\repository</localRepository> | 7 | + <!-- 锟斤拷锟截仓匡拷 --> |
| 8 | +<!-- <localRepository>F:\maven\repository</localRepository>--> | ||
| 9 | 9 | ||
| 10 | - <!-- 配置私服中deploy的账号 --> | 10 | + <!-- 锟斤拷锟斤拷私锟斤拷锟斤拷deploy锟斤拷锟剿猴拷 --> |
| 11 | <servers> | 11 | <servers> |
| 12 | <server> | 12 | <server> |
| 13 | <id>sl-releases</id> | 13 | <id>sl-releases</id> |
| @@ -21,7 +21,7 @@ | @@ -21,7 +21,7 @@ | ||
| 21 | </server> | 21 | </server> |
| 22 | </servers> | 22 | </servers> |
| 23 | 23 | ||
| 24 | - <!-- 使用阿里云maven镜像,排除私服资源库 --> | 24 | + <!-- 使锟矫帮拷锟斤拷锟斤拷maven锟斤拷锟斤拷锟脚筹拷私锟斤拷锟斤拷源锟斤拷 --> |
| 25 | <mirrors> | 25 | <mirrors> |
| 26 | <mirror> | 26 | <mirror> |
| 27 | <id>mirror</id> | 27 | <id>mirror</id> |
| @@ -34,7 +34,7 @@ | @@ -34,7 +34,7 @@ | ||
| 34 | <profiles> | 34 | <profiles> |
| 35 | <profile> | 35 | <profile> |
| 36 | <id>sl</id> | 36 | <id>sl</id> |
| 37 | - <!-- 配置项目deploy的地址 --> | 37 | + <!-- 锟斤拷锟斤拷锟斤拷目deploy锟侥碉拷址 --> |
| 38 | <properties> | 38 | <properties> |
| 39 | <altReleaseDeploymentRepository> | 39 | <altReleaseDeploymentRepository> |
| 40 | sl-releases::default::http://maven.sl-express.com/nexus/content/repositories/releases/ | 40 | sl-releases::default::http://maven.sl-express.com/nexus/content/repositories/releases/ |
| @@ -43,7 +43,7 @@ | @@ -43,7 +43,7 @@ | ||
| 43 | sl-snapshots::default::http://maven.sl-express.com/nexus/content/repositories/snapshots/ | 43 | sl-snapshots::default::http://maven.sl-express.com/nexus/content/repositories/snapshots/ |
| 44 | </altSnapshotDeploymentRepository> | 44 | </altSnapshotDeploymentRepository> |
| 45 | </properties> | 45 | </properties> |
| 46 | - <!-- 配置项目下载依赖的私服地址 --> | 46 | + <!-- 锟斤拷锟斤拷锟斤拷目锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷私锟斤拷锟斤拷址 --> |
| 47 | <repositories> | 47 | <repositories> |
| 48 | <repository> | 48 | <repository> |
| 49 | <id>sl-releases</id> | 49 | <id>sl-releases</id> |
| @@ -70,7 +70,7 @@ | @@ -70,7 +70,7 @@ | ||
| 70 | </profiles> | 70 | </profiles> |
| 71 | 71 | ||
| 72 | <activeProfiles> | 72 | <activeProfiles> |
| 73 | - <!-- 激活配置 --> | 73 | + <!-- 锟斤拷锟斤拷锟斤拷锟斤拷 --> |
| 74 | <activeProfile>sl</activeProfile> | 74 | <activeProfile>sl</activeProfile> |
| 75 | </activeProfiles> | 75 | </activeProfiles> |
| 76 | 76 |
sl-express-ms-transport-service/src/main/java/com/sl/transport/enums/ExceptionEnum.java
| @@ -16,7 +16,8 @@ public enum ExceptionEnum implements BaseExceptionEnum { | @@ -16,7 +16,8 @@ public enum ExceptionEnum implements BaseExceptionEnum { | ||
| 16 | TRANSPORT_LINE_ALREADY_EXISTS(1003, "路线已经存在"), | 16 | TRANSPORT_LINE_ALREADY_EXISTS(1003, "路线已经存在"), |
| 17 | TRANSPORT_LINE_NOT_FOUND(1004, "路线不存在"), | 17 | TRANSPORT_LINE_NOT_FOUND(1004, "路线不存在"), |
| 18 | TRANSPORT_LINE_TYPE_ERROR(1005, "路线类型错误"), | 18 | TRANSPORT_LINE_TYPE_ERROR(1005, "路线类型错误"), |
| 19 | - ORGAN_TYPE_ERROR(1006, "机构类型错误"); | 19 | + ORGAN_TYPE_ERROR(1006, "机构类型错误"), |
| 20 | + TRANSPORT_LINE_ORGAN_CANNOT_SAME(1007, "起点、终点机构不能为空"); | ||
| 20 | 21 | ||
| 21 | private Integer code; | 22 | private Integer code; |
| 22 | private Integer status; | 23 | private Integer status; |
sl-express-ms-transport-service/src/main/java/com/sl/transport/mq/AuthMQListener.java
0 → 100644
| 1 | +package com.sl.transport.mq; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.util.StrUtil; | ||
| 4 | +import cn.hutool.json.JSONObject; | ||
| 5 | +import cn.hutool.json.JSONUtil; | ||
| 6 | +import com.sl.transport.common.constant.Constants; | ||
| 7 | +import com.sl.transport.entity.node.AgencyEntity; | ||
| 8 | +import com.sl.transport.entity.node.BaseEntity; | ||
| 9 | +import com.sl.transport.entity.node.OLTEntity; | ||
| 10 | +import com.sl.transport.entity.node.TLTEntity; | ||
| 11 | +import com.sl.transport.enums.OrganTypeEnum; | ||
| 12 | +import com.sl.transport.service.IService; | ||
| 13 | +import com.sl.transport.utils.OrganServiceFactory; | ||
| 14 | +import lombok.extern.slf4j.Slf4j; | ||
| 15 | +import org.springframework.amqp.core.ExchangeTypes; | ||
| 16 | +import org.springframework.amqp.rabbit.annotation.Exchange; | ||
| 17 | +import org.springframework.amqp.rabbit.annotation.Queue; | ||
| 18 | +import org.springframework.amqp.rabbit.annotation.QueueBinding; | ||
| 19 | +import org.springframework.amqp.rabbit.annotation.RabbitListener; | ||
| 20 | +import org.springframework.stereotype.Component; | ||
| 21 | + | ||
| 22 | +/** | ||
| 23 | + * 对于权限管家消息的处理 | ||
| 24 | + */ | ||
| 25 | +@Slf4j | ||
| 26 | +@Component | ||
| 27 | +public class AuthMQListener { | ||
| 28 | + | ||
| 29 | + @RabbitListener(bindings = @QueueBinding( | ||
| 30 | + value = @Queue(name = Constants.MQ.Queues.AUTH_TRANSPORT), | ||
| 31 | + exchange = @Exchange(name = "${rabbitmq.exchange}", type = ExchangeTypes.TOPIC), | ||
| 32 | + key = "#" | ||
| 33 | + )) | ||
| 34 | + public void listenAgencyMsg(String msg) { | ||
| 35 | + log.info("接收到消息->{}", msg); | ||
| 36 | + JSONObject jsonObject = JSONUtil.parseObj(msg); | ||
| 37 | + | ||
| 38 | +// 获取type的值,如果不为ORG,直接return | ||
| 39 | + String type = jsonObject.getStr("type"); | ||
| 40 | + if (!StrUtil.equalsIgnoreCase(type, "ORG")) { | ||
| 41 | +// 非机构消息 | ||
| 42 | + return; | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | +// 获取json中其他值 operation操作类型 content是数组0号下表 | ||
| 46 | + String operation = jsonObject.getStr("operation"); | ||
| 47 | + JSONObject content = (JSONObject) jsonObject.getJSONArray("content").getObj(0); | ||
| 48 | + | ||
| 49 | +// 取到content中的元素后,获取name机构名称 parentId父机构ID | ||
| 50 | + String name = content.getStr("name"); | ||
| 51 | + Long parentId = content.getLong("parentId"); | ||
| 52 | + | ||
| 53 | + IService iService; | ||
| 54 | + BaseEntity baseEntity; | ||
| 55 | + if (StrUtil.endWith(name, "转运中心")) { | ||
| 56 | +// 一级转运中心 | ||
| 57 | + iService = OrganServiceFactory.getBean(OrganTypeEnum.OLT.getCode()); | ||
| 58 | + baseEntity = new OLTEntity(); | ||
| 59 | + baseEntity.setParentId(0L); | ||
| 60 | + } else if (StrUtil.endWith(name, "分拣中心")) { | ||
| 61 | +// 二级转运中心 | ||
| 62 | + iService = OrganServiceFactory.getBean(OrganTypeEnum.TLT.getCode()); | ||
| 63 | + baseEntity = new TLTEntity(); | ||
| 64 | + baseEntity.setParentId(parentId); | ||
| 65 | + } else if (StrUtil.endWith(name, "营业部")) { | ||
| 66 | +// 网点 | ||
| 67 | + iService = OrganServiceFactory.getBean(OrganTypeEnum.AGENCY.getCode()); | ||
| 68 | + baseEntity = new AgencyEntity(); | ||
| 69 | + baseEntity.setParentId(parentId); | ||
| 70 | + } else { | ||
| 71 | + return; | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + baseEntity.setBid(content.getLong("id")); | ||
| 75 | + baseEntity.setName(name); | ||
| 76 | + baseEntity.setStatus(content.getBool("status")); | ||
| 77 | + | ||
| 78 | + | ||
| 79 | + switch (operation) { | ||
| 80 | + case "ADD": { | ||
| 81 | + iService.create(baseEntity); | ||
| 82 | + break; | ||
| 83 | + } | ||
| 84 | + case "UPDATE":{ | ||
| 85 | + iService.update(baseEntity); | ||
| 86 | + break; | ||
| 87 | + } | ||
| 88 | + case "DEL":{ | ||
| 89 | + iService.deleteByBid(baseEntity.getBid()); | ||
| 90 | + break; | ||
| 91 | + } | ||
| 92 | + } | ||
| 93 | + } | ||
| 94 | + | ||
| 95 | + | ||
| 96 | +} |
sl-express-ms-transport-service/src/main/java/com/sl/transport/repository/impl/OrganRepositoryImpl.java
0 → 100644
| 1 | +package com.sl.transport.repository.impl; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.collection.ListUtil; | ||
| 5 | +import cn.hutool.core.util.ObjectUtil; | ||
| 6 | +import cn.hutool.core.util.StrUtil; | ||
| 7 | +import com.sl.transport.common.util.BeanUtil; | ||
| 8 | +import com.sl.transport.domain.OrganDTO; | ||
| 9 | +import com.sl.transport.enums.OrganTypeEnum; | ||
| 10 | +import com.sl.transport.repository.OrganRepository; | ||
| 11 | +import jdk.jfr.Registered; | ||
| 12 | +import org.neo4j.driver.internal.InternalPoint2D; | ||
| 13 | +import org.springframework.beans.BeanUtils; | ||
| 14 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 15 | +import org.springframework.data.neo4j.core.Neo4jClient; | ||
| 16 | +import org.springframework.stereotype.Repository; | ||
| 17 | + | ||
| 18 | +import java.util.List; | ||
| 19 | +import java.util.Map; | ||
| 20 | + | ||
| 21 | +@Repository | ||
| 22 | +public class OrganRepositoryImpl implements OrganRepository { | ||
| 23 | + | ||
| 24 | + @Autowired | ||
| 25 | + private Neo4jClient neo4jClient; | ||
| 26 | + | ||
| 27 | + @Override | ||
| 28 | + public OrganDTO findByBid(Long bid) { | ||
| 29 | + String cypherQuery = StrUtil.format("MATCH (n)\n" + | ||
| 30 | + "WHERE n.bid = {}\n" + | ||
| 31 | + "RETURN n", bid); | ||
| 32 | + return CollUtil.getFirst(executeQuery(cypherQuery)); | ||
| 33 | + } | ||
| 34 | + | ||
| 35 | + @Override | ||
| 36 | + public List<OrganDTO> findByBids(List<Long> bids) { | ||
| 37 | + String cypherQuery = StrUtil.format("MATCH (n)\n" + | ||
| 38 | + "WHERE n.bid in {}\n" + | ||
| 39 | + "RETURN n", bids); | ||
| 40 | + return executeQuery(cypherQuery); | ||
| 41 | + } | ||
| 42 | + | ||
| 43 | + @Override | ||
| 44 | + public List<OrganDTO> findAll(String name) { | ||
| 45 | + name = StrUtil.removeAll(name, '\'', '"'); | ||
| 46 | + String cypherQuery = StrUtil.isEmpty(name) ? | ||
| 47 | + "MATCH (n) RETURN n" : | ||
| 48 | + StrUtil.format("MATCH (n) WHERE n.name CONTAINS '{}' RETURN n", name); | ||
| 49 | + return executeQuery(cypherQuery); | ||
| 50 | + } | ||
| 51 | + | ||
| 52 | + private List<OrganDTO> executeQuery(String cypherQuery) { | ||
| 53 | + return ListUtil.toList(this.neo4jClient.query(cypherQuery) | ||
| 54 | + .fetchAs(OrganDTO.class) | ||
| 55 | + .mappedBy(((typeSystem, record) -> { | ||
| 56 | + Map<String, Object> map = record.get("n").asMap(); | ||
| 57 | + OrganDTO organDTO = BeanUtil.toBean(map, OrganDTO.class); | ||
| 58 | + InternalPoint2D location = (InternalPoint2D) map.get("location"); | ||
| 59 | + if (ObjectUtil.isNotEmpty(location)) { | ||
| 60 | + organDTO.setLongitude(location.x()); | ||
| 61 | + organDTO.setLatitude(location.y()); | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | +// 获取类型 | ||
| 65 | + String type = CollUtil.getFirst(record.get("n").asNode().labels()); | ||
| 66 | + organDTO.setType(OrganTypeEnum.valueOf(type).getCode()); | ||
| 67 | + return organDTO; | ||
| 68 | + })).all() | ||
| 69 | + ); | ||
| 70 | + } | ||
| 71 | +} |
sl-express-ms-transport-service/src/main/java/com/sl/transport/repository/impl/TransportLineRepositoryImpl.java
0 → 100644
| 1 | +package com.sl.transport.repository.impl; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.bean.BeanUtil; | ||
| 4 | +import cn.hutool.core.collection.CollUtil; | ||
| 5 | +import cn.hutool.core.collection.ListUtil; | ||
| 6 | +import cn.hutool.core.convert.Convert; | ||
| 7 | +import cn.hutool.core.map.MapUtil; | ||
| 8 | +import cn.hutool.core.util.PageUtil; | ||
| 9 | +import cn.hutool.core.util.StrUtil; | ||
| 10 | +import com.sl.transport.common.util.PageResponse; | ||
| 11 | +import com.sl.transport.domain.TransportLineNodeDTO; | ||
| 12 | +import com.sl.transport.domain.TransportLineSearchDTO; | ||
| 13 | +import com.sl.transport.entity.line.TransportLine; | ||
| 14 | +import com.sl.transport.entity.node.AgencyEntity; | ||
| 15 | +import com.sl.transport.entity.node.BaseEntity; | ||
| 16 | +import com.sl.transport.repository.TransportLineRepository; | ||
| 17 | +import com.sl.transport.utils.TransportLineUtils; | ||
| 18 | +import org.neo4j.driver.internal.value.PathValue; | ||
| 19 | +import org.neo4j.driver.types.Relationship; | ||
| 20 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 21 | +import org.springframework.data.neo4j.core.Neo4jClient; | ||
| 22 | +import org.springframework.stereotype.Repository; | ||
| 23 | +import org.neo4j.driver.Record; | ||
| 24 | +import org.springframework.data.neo4j.core.schema.Node; | ||
| 25 | + | ||
| 26 | +import java.util.Collection; | ||
| 27 | +import java.util.List; | ||
| 28 | +import java.util.Map; | ||
| 29 | +import java.util.Optional; | ||
| 30 | + | ||
| 31 | +/** | ||
| 32 | + * 对于路线的各种操作 | ||
| 33 | + */ | ||
| 34 | +@Repository | ||
| 35 | +public class TransportLineRepositoryImpl implements TransportLineRepository { | ||
| 36 | + | ||
| 37 | + @Autowired | ||
| 38 | + private Neo4jClient neo4jClient; | ||
| 39 | + | ||
| 40 | + @Override | ||
| 41 | + public TransportLineNodeDTO findShortestPath(AgencyEntity start, AgencyEntity end) { | ||
| 42 | + return this.findShortestPath(start, end, 10); | ||
| 43 | + } | ||
| 44 | + | ||
| 45 | + @Override | ||
| 46 | + public TransportLineNodeDTO findShortestPath(AgencyEntity start, AgencyEntity end, int depth) { | ||
| 47 | + //获取网点数据在Neo4j中的类型 | ||
| 48 | + String type = AgencyEntity.class.getAnnotation(Node.class).value()[0]; | ||
| 49 | + //构造查询语句 | ||
| 50 | + String cypherQuery = StrUtil.format( | ||
| 51 | + "MATCH path = shortestPath((start:{}) -[*..{}]-> (end:{}))\n" + | ||
| 52 | + "WHERE start.bid = $startId AND end.bid = $endId AND start.status = true AND end.status = true\n" + | ||
| 53 | + "RETURN path", type, depth, type); | ||
| 54 | + Collection<TransportLineNodeDTO> transportLineNodeDTOS = this.executeQueryPath(cypherQuery, start, end); | ||
| 55 | + if (CollUtil.isEmpty(transportLineNodeDTOS)) { | ||
| 56 | + return null; | ||
| 57 | + } | ||
| 58 | + for (TransportLineNodeDTO transportLineNodeDTO : transportLineNodeDTOS) { | ||
| 59 | + return transportLineNodeDTO; | ||
| 60 | + } | ||
| 61 | + return null; | ||
| 62 | + } | ||
| 63 | + | ||
| 64 | + private List<TransportLineNodeDTO> executeQueryPath(String cypherQuery, AgencyEntity start, AgencyEntity end) { | ||
| 65 | + return ListUtil.toList(this.neo4jClient.query(cypherQuery) | ||
| 66 | + .bind(start.getBid()).to("startId") //设置参数 | ||
| 67 | + .bind(end.getBid()).to("endId") //设置参数 | ||
| 68 | + .fetchAs(TransportLineNodeDTO.class) //设置响应的类型 | ||
| 69 | + .mappedBy((typeSystem, record) -> { //对结果进行封装处理 | ||
| 70 | + PathValue pathValue = (PathValue) record.get(0); | ||
| 71 | + return TransportLineUtils.convert(pathValue); | ||
| 72 | + }).all()); | ||
| 73 | + } | ||
| 74 | + | ||
| 75 | + @Override | ||
| 76 | + public List<TransportLineNodeDTO> findPathList(AgencyEntity start, AgencyEntity end, int depth, int limit) { | ||
| 77 | + //获取网点数据在Neo4j中的类型 | ||
| 78 | + String type = AgencyEntity.class.getAnnotation(Node.class).value()[0]; | ||
| 79 | + //构造查询语句 | ||
| 80 | + String cypherQuery = StrUtil.format( | ||
| 81 | + "MATCH path = (start:{}) -[*..{}]-> (end:{})\n" + | ||
| 82 | + "WHERE start.bid = $startId AND end.bid = $endId AND start.status = true AND end.status = true\n" + | ||
| 83 | + "UNWIND relationships(path) AS r\n" + | ||
| 84 | + "WITH sum(r.cost) AS cost, path\n" + | ||
| 85 | + "RETURN path ORDER BY cost ASC, LENGTH(path) ASC LIMIT {}", type, depth, type, limit); | ||
| 86 | + return this.executeQueryPath(cypherQuery, start, end); | ||
| 87 | + } | ||
| 88 | + | ||
| 89 | + @Override | ||
| 90 | + public Long queryCount(BaseEntity firstNode, BaseEntity secondNode) { | ||
| 91 | + String firstNodeType = firstNode.getClass().getAnnotation(Node.class).value()[0]; | ||
| 92 | + String secondNodeType = secondNode.getClass().getAnnotation(Node.class).value()[0]; | ||
| 93 | + String cypherQuery = StrUtil.format( | ||
| 94 | + "MATCH (m:{}) -[r]- (n:{})\n" + | ||
| 95 | + "WHERE m.bid = $firstBid AND n.bid = $secondBid\n" + | ||
| 96 | + "RETURN count(r) AS c", firstNodeType, secondNodeType); | ||
| 97 | + Optional<Long> optional = this.neo4jClient.query(cypherQuery) | ||
| 98 | + .bind(firstNode.getBid()).to("firstBid") | ||
| 99 | + .bind(secondNode.getBid()).to("secondBid") | ||
| 100 | + .fetchAs(Long.class) | ||
| 101 | + .mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))) | ||
| 102 | + .one(); | ||
| 103 | + return optional.orElse(0L); | ||
| 104 | + } | ||
| 105 | + | ||
| 106 | + @Override | ||
| 107 | + public Long create(BaseEntity firstNode, BaseEntity secondNode, TransportLine transportLine) { | ||
| 108 | + String firstNodeType = firstNode.getClass().getAnnotation(Node.class).value()[0]; | ||
| 109 | + String secondNodeType = secondNode.getClass().getAnnotation(Node.class).value()[0]; | ||
| 110 | + String cypherQuery = StrUtil.format( | ||
| 111 | + "MATCH (m:{} {bid : $firstBid})\n" + | ||
| 112 | + "WITH m\n" + | ||
| 113 | + "MATCH (n:{} {bid : $secondBid})\n" + | ||
| 114 | + "WITH m,n\n" + | ||
| 115 | + "CREATE\n" + | ||
| 116 | + " (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" + | ||
| 117 | + " (m) <-[:OUT_LINE {cost:$cost, number:$number, type:$type, name:$name, distance:$distance, time:$time, extra:$extra, startOrganId:$endOrganId, endOrganId:$startOrganId, created:$created, updated:$updated}]- (n)\n" + | ||
| 118 | + "RETURN count(r) AS c", firstNodeType, secondNodeType); | ||
| 119 | + Optional<Long> optional = this.neo4jClient.query(cypherQuery) | ||
| 120 | + .bindAll(BeanUtil.beanToMap(transportLine)) | ||
| 121 | + .bind(firstNode.getBid()).to("firstBid") | ||
| 122 | + .bind(secondNode.getBid()).to("secondBid") | ||
| 123 | + .fetchAs(Long.class) | ||
| 124 | + .mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))) | ||
| 125 | + .one(); | ||
| 126 | + return optional.orElse(0L); | ||
| 127 | + } | ||
| 128 | + | ||
| 129 | + @Override | ||
| 130 | + public Long update(TransportLine transportLine) { | ||
| 131 | + String cypherQuery = "MATCH () -[r]-> ()\n" + | ||
| 132 | + "WHERE id(r) = $id\n" + | ||
| 133 | + "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" + | ||
| 134 | + "RETURN count(r) AS c"; | ||
| 135 | + Optional<Long> optional = this.neo4jClient.query(cypherQuery) | ||
| 136 | + .bindAll(BeanUtil.beanToMap(transportLine)) | ||
| 137 | + .fetchAs(Long.class) | ||
| 138 | + .mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))) | ||
| 139 | + .one(); | ||
| 140 | + return optional.orElse(0L); | ||
| 141 | + } | ||
| 142 | + | ||
| 143 | + @Override | ||
| 144 | + public Long remove(Long lineId) { | ||
| 145 | + String cypherQuery = "MATCH () -[r]-> ()\n" + | ||
| 146 | + "WHERE id(r) = $lineId\n" + | ||
| 147 | + "DETACH DELETE r\n" + | ||
| 148 | + "RETURN count(r) AS c"; | ||
| 149 | + Optional<Long> optional = this.neo4jClient.query(cypherQuery) | ||
| 150 | + .bind(lineId).to("lineId") | ||
| 151 | + .fetchAs(Long.class) | ||
| 152 | + .mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))) | ||
| 153 | + .one(); | ||
| 154 | + return optional.orElse(0L); | ||
| 155 | + } | ||
| 156 | + | ||
| 157 | + @Override | ||
| 158 | + public PageResponse<TransportLine> queryPageList(TransportLineSearchDTO transportLineSearchDTO) { | ||
| 159 | + int page = Math.max(transportLineSearchDTO.getPage(), 1); | ||
| 160 | + int pageSize = transportLineSearchDTO.getPageSize(); | ||
| 161 | + int skip = (page - 1) * pageSize; | ||
| 162 | + Map<String, Object> searchParam = BeanUtil.beanToMap(transportLineSearchDTO, false, true); | ||
| 163 | + MapUtil.removeAny(searchParam, "page", "pageSize"); //构建查询语句,第一个是查询数据,第二个是查询数量 | ||
| 164 | + String[] cyphers = this.buildPageQueryCypher(searchParam); | ||
| 165 | + String cypherQuery = cyphers[0]; | ||
| 166 | + | ||
| 167 | + //数据 | ||
| 168 | + List<TransportLine> list = ListUtil.toList(this.neo4jClient.query(cypherQuery) | ||
| 169 | + .bind(skip).to("skip") | ||
| 170 | + .bind(pageSize).to("limit") | ||
| 171 | + .bindAll(searchParam) | ||
| 172 | + .fetchAs(TransportLine.class) | ||
| 173 | + .mappedBy((typeSystem, record) -> { | ||
| 174 | + //封装数据 | ||
| 175 | + return this.toTransportLine(record); | ||
| 176 | + }).all()); | ||
| 177 | + | ||
| 178 | + // 数据总数 | ||
| 179 | + String countCypher = cyphers[1]; | ||
| 180 | + Long total = this.neo4jClient.query(countCypher) | ||
| 181 | + .bindAll(searchParam) | ||
| 182 | + .fetchAs(Long.class) | ||
| 183 | + .mappedBy((typeSystem, record) -> Convert.toLong(record.get("c"))) | ||
| 184 | + .one().orElse(0L); | ||
| 185 | + | ||
| 186 | + PageResponse<TransportLine> pageResponse = new PageResponse<>(); | ||
| 187 | + pageResponse.setPage(page); | ||
| 188 | + pageResponse.setPageSize(pageSize); | ||
| 189 | + pageResponse.setItems(list); | ||
| 190 | + pageResponse.setCounts(total); | ||
| 191 | + Long pages = Convert.toLong(PageUtil.totalPage(Convert.toInt(total), pageSize)); | ||
| 192 | + pageResponse.setPages(pages); | ||
| 193 | + | ||
| 194 | + return pageResponse; | ||
| 195 | + } | ||
| 196 | + | ||
| 197 | + private String[] buildPageQueryCypher(Map<String, Object> searchParam) { | ||
| 198 | + String queryCypher; | ||
| 199 | + String countCypher; | ||
| 200 | + if (CollUtil.isEmpty(searchParam)) { | ||
| 201 | + //无参数 | ||
| 202 | + queryCypher = "MATCH (m) -[r]-> (n) RETURN m,r,n ORDER BY id(r) DESC SKIP $skip LIMIT $limit"; | ||
| 203 | + countCypher = "MATCH () -[r]-> () RETURN count(r) AS c"; | ||
| 204 | + } else { | ||
| 205 | + //有参数 | ||
| 206 | + String cypherPrefix = "MATCH (m) -[r]-> (n)"; | ||
| 207 | + StringBuilder sb = new StringBuilder(); | ||
| 208 | + sb.append(cypherPrefix).append(" WHERE 1=1 "); | ||
| 209 | + for (String key : searchParam.keySet()) { | ||
| 210 | + Object value = searchParam.get(key); | ||
| 211 | + if (value instanceof String) { | ||
| 212 | + if (StrUtil.isNotBlank(Convert.toStr(value))) { | ||
| 213 | + sb.append(StrUtil.format("AND r.{} CONTAINS ${} \n", key, key)); | ||
| 214 | + } | ||
| 215 | + } else { | ||
| 216 | + sb.append(StrUtil.format("AND r.{} = ${} \n", key, key)); | ||
| 217 | + } | ||
| 218 | + } | ||
| 219 | + String cypher = sb.toString(); | ||
| 220 | + queryCypher = cypher + "RETURN m,r,n ORDER BY id(r) DESC SKIP $skip LIMIT $limit"; | ||
| 221 | + countCypher = cypher + "RETURN count(r) AS c"; | ||
| 222 | + } | ||
| 223 | + return new String[]{queryCypher, countCypher}; | ||
| 224 | + } | ||
| 225 | + | ||
| 226 | + @Override | ||
| 227 | + public List<TransportLine> queryByIds(Long... ids) { | ||
| 228 | + String cypherQuery = "MATCH (m) -[r]-> (n)\n" + | ||
| 229 | + "WHERE id(r) in $ids\n" + | ||
| 230 | + "RETURN m,r,n"; | ||
| 231 | + return ListUtil.toList(this.neo4jClient.query(cypherQuery) | ||
| 232 | + .bind(ids).to("ids") | ||
| 233 | + .fetchAs(TransportLine.class) | ||
| 234 | + .mappedBy((typeSystem, record) -> { | ||
| 235 | + //封装数据 | ||
| 236 | + return this.toTransportLine(record); | ||
| 237 | + }).all()); | ||
| 238 | + } | ||
| 239 | + | ||
| 240 | + private TransportLine toTransportLine(Record record) { | ||
| 241 | + org.neo4j.driver.types.Node startNode = record.get("m").asNode(); | ||
| 242 | + org.neo4j.driver.types.Node endNode = record.get("n").asNode(); | ||
| 243 | + Relationship relationship = record.get("r").asRelationship(); | ||
| 244 | + Map<String, Object> map = relationship.asMap(); | ||
| 245 | + | ||
| 246 | + TransportLine transportLine = BeanUtil.toBeanIgnoreError(map, TransportLine.class); | ||
| 247 | + transportLine.setStartOrganName(startNode.get("name").asString()); | ||
| 248 | + transportLine.setStartOrganId(startNode.get("bid").asLong()); | ||
| 249 | + transportLine.setEndOrganName(endNode.get("name").asString()); | ||
| 250 | + transportLine.setEndOrganId(endNode.get("bid").asLong()); | ||
| 251 | + transportLine.setId(relationship.id()); | ||
| 252 | + return transportLine; | ||
| 253 | + } | ||
| 254 | + | ||
| 255 | + | ||
| 256 | + @Override | ||
| 257 | + public TransportLine queryById(Long id) { | ||
| 258 | + List<TransportLine> transportLines = this.queryByIds(id); | ||
| 259 | + if (CollUtil.isNotEmpty(transportLines)) { | ||
| 260 | + return transportLines.get(0); | ||
| 261 | + } | ||
| 262 | + return null; | ||
| 263 | + } | ||
| 264 | +} |
sl-express-ms-transport-service/src/main/java/com/sl/transport/service/impl/AgencyServiceImpl.java
0 → 100644
| 1 | +package com.sl.transport.service.impl; | ||
| 2 | + | ||
| 3 | +import com.sl.transport.entity.node.AgencyEntity; | ||
| 4 | +import com.sl.transport.repository.AgencyRepository; | ||
| 5 | +import com.sl.transport.service.AgencyService; | ||
| 6 | +import org.springframework.stereotype.Service; | ||
| 7 | + | ||
| 8 | +@Service | ||
| 9 | +public class AgencyServiceImpl extends ServiceImpl<AgencyRepository, AgencyEntity> implements AgencyService { | ||
| 10 | +} |
sl-express-ms-transport-service/src/main/java/com/sl/transport/service/impl/CostConfigurationServiceImpl.java
| @@ -23,23 +23,23 @@ import java.util.stream.Collectors; | @@ -23,23 +23,23 @@ import java.util.stream.Collectors; | ||
| 23 | */ | 23 | */ |
| 24 | @Service | 24 | @Service |
| 25 | public class CostConfigurationServiceImpl implements CostConfigurationService { | 25 | public class CostConfigurationServiceImpl implements CostConfigurationService { |
| 26 | - | ||
| 27 | - @Resource | ||
| 28 | - private StringRedisTemplate stringRedisTemplate; | ||
| 29 | - | ||
| 30 | /** | 26 | /** |
| 31 | * 成本配置 redis key | 27 | * 成本配置 redis key |
| 32 | */ | 28 | */ |
| 33 | - static final String SL_TRANSPORT_COST_REDIS_KEY = "SL_TRANSPORT_COST_CONFIGURATION"; | 29 | + private static final String SL_TRANSPORT_COST_REDIS_KEY = "SL_TRANSPORT_COST_CONFIGURATION"; |
| 34 | 30 | ||
| 35 | /** | 31 | /** |
| 36 | * 默认成本配置 | 32 | * 默认成本配置 |
| 37 | */ | 33 | */ |
| 38 | - static final Map<Object, Object> DEFAULT_COST = Map.of( | 34 | + private static final Map<Object, Object> DEFAULT_COST = Map.of( |
| 39 | TransportLineEnum.TRUNK_LINE.getCode(), 0.8, | 35 | TransportLineEnum.TRUNK_LINE.getCode(), 0.8, |
| 40 | TransportLineEnum.BRANCH_LINE.getCode(), 1.2, | 36 | TransportLineEnum.BRANCH_LINE.getCode(), 1.2, |
| 41 | TransportLineEnum.CONNECT_LINE.getCode(), 1.5); | 37 | TransportLineEnum.CONNECT_LINE.getCode(), 1.5); |
| 42 | 38 | ||
| 39 | + @Resource | ||
| 40 | + private StringRedisTemplate stringRedisTemplate; | ||
| 41 | + | ||
| 42 | + | ||
| 43 | /** | 43 | /** |
| 44 | * 查询成本配置 | 44 | * 查询成本配置 |
| 45 | * | 45 | * |
sl-express-ms-transport-service/src/main/java/com/sl/transport/service/impl/OLTServiceImpl.java
0 → 100644
| 1 | +package com.sl.transport.service.impl; | ||
| 2 | + | ||
| 3 | +import com.sl.transport.entity.node.OLTEntity; | ||
| 4 | +import com.sl.transport.repository.OLTRepository; | ||
| 5 | +import com.sl.transport.service.OLTService; | ||
| 6 | +import org.springframework.stereotype.Service; | ||
| 7 | + | ||
| 8 | +@Service | ||
| 9 | +public class OLTServiceImpl extends ServiceImpl<OLTRepository, OLTEntity> implements OLTService { | ||
| 10 | +} |
sl-express-ms-transport-service/src/main/java/com/sl/transport/service/impl/OrganServiceImpl.java
0 → 100644
| 1 | +package com.sl.transport.service.impl; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.collection.CollUtil; | ||
| 4 | +import cn.hutool.core.lang.tree.Tree; | ||
| 5 | +import cn.hutool.core.lang.tree.TreeUtil; | ||
| 6 | +import cn.hutool.core.util.ObjectUtil; | ||
| 7 | +import com.fasterxml.jackson.core.JsonParseException; | ||
| 8 | +import com.fasterxml.jackson.core.JsonProcessingException; | ||
| 9 | +import com.fasterxml.jackson.databind.ObjectMapper; | ||
| 10 | +import com.sl.transport.common.exception.SLException; | ||
| 11 | +import com.sl.transport.common.util.BeanUtil; | ||
| 12 | +import com.sl.transport.domain.OrganDTO; | ||
| 13 | +import com.sl.transport.enums.ExceptionEnum; | ||
| 14 | +import com.sl.transport.repository.OrganRepository; | ||
| 15 | +import com.sl.transport.service.OrganService; | ||
| 16 | +import org.springframework.beans.BeanUtils; | ||
| 17 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 18 | +import org.springframework.stereotype.Service; | ||
| 19 | + | ||
| 20 | +import java.util.List; | ||
| 21 | + | ||
| 22 | +@Service | ||
| 23 | +public class OrganServiceImpl implements OrganService { | ||
| 24 | + | ||
| 25 | + @Autowired | ||
| 26 | + private OrganRepository organRepository; | ||
| 27 | + | ||
| 28 | + @Autowired | ||
| 29 | + private ObjectMapper objectMapper; | ||
| 30 | + | ||
| 31 | + @Override | ||
| 32 | + public OrganDTO findByBid(Long bid) { | ||
| 33 | + OrganDTO organDTO = this.organRepository.findByBid(bid); | ||
| 34 | + if (ObjectUtil.isNotEmpty(organDTO)) { | ||
| 35 | + return organDTO; | ||
| 36 | + } | ||
| 37 | + throw new SLException(ExceptionEnum.ORGAN_NOT_FOUND); | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + @Override | ||
| 41 | + public List<OrganDTO> findByBids(List<Long> bids) { | ||
| 42 | + List<OrganDTO> organDTOS = this.organRepository.findByBids(bids); | ||
| 43 | + if (ObjectUtil.isNotEmpty(organDTOS)) { | ||
| 44 | + return organDTOS; | ||
| 45 | + } | ||
| 46 | + throw new SLException(ExceptionEnum.ORGAN_NOT_FOUND); | ||
| 47 | + } | ||
| 48 | + | ||
| 49 | + @Override | ||
| 50 | + public List<OrganDTO> findAll(String name) { | ||
| 51 | + return this.organRepository.findAll(name); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + @Override | ||
| 55 | + public String findAllTree() { | ||
| 56 | + List<OrganDTO> organList = this.findAll(null); | ||
| 57 | + if (CollUtil.isEmpty(organList)) { | ||
| 58 | + return ""; | ||
| 59 | + } | ||
| 60 | + | ||
| 61 | +// 构造树结构 | ||
| 62 | + List<Tree<Long>> treeNodes = TreeUtil.build(organList, 0L, | ||
| 63 | + ((organDTO, tree) -> { | ||
| 64 | + tree.setId(organDTO.getId()); | ||
| 65 | + tree.setParentId(organDTO.getParentId()); | ||
| 66 | + tree.putAll(BeanUtil.beanToMap(organDTO)); | ||
| 67 | + tree.remove("bid"); | ||
| 68 | + })); | ||
| 69 | + | ||
| 70 | + try { | ||
| 71 | + return this.objectMapper.writeValueAsString(treeNodes); | ||
| 72 | + } catch (JsonProcessingException e) { | ||
| 73 | + throw new SLException("序列化JSON出错!", e); | ||
| 74 | + } | ||
| 75 | + | ||
| 76 | + } | ||
| 77 | +} |
sl-express-ms-transport-service/src/main/java/com/sl/transport/service/impl/ServiceImpl.java
0 → 100644
| 1 | +package com.sl.transport.service.impl; | ||
| 2 | + | ||
| 3 | +import com.sl.transport.entity.node.BaseEntity; | ||
| 4 | +import com.sl.transport.repository.BaseRepository; | ||
| 5 | +import com.sl.transport.service.IService; | ||
| 6 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 7 | +import org.springframework.stereotype.Service; | ||
| 8 | + | ||
| 9 | +/** | ||
| 10 | + * 基础服务的实现 | ||
| 11 | + * @param <R> | ||
| 12 | + * @param <T> | ||
| 13 | + */ | ||
| 14 | +public class ServiceImpl<R extends BaseRepository,T extends BaseEntity> implements IService<T> { | ||
| 15 | + | ||
| 16 | + @Autowired | ||
| 17 | + private R repository; | ||
| 18 | + | ||
| 19 | + @Override | ||
| 20 | + public T queryByBid(Long bid) { | ||
| 21 | + return (T) this.repository.findByBid(bid).orElse(null); | ||
| 22 | + } | ||
| 23 | + | ||
| 24 | + @Override | ||
| 25 | + public T create(T t) { | ||
| 26 | + return (T) this.repository.save(t); | ||
| 27 | + } | ||
| 28 | + | ||
| 29 | + @Override | ||
| 30 | + public T update(T t) { | ||
| 31 | +// id由neo4j自动生成 | ||
| 32 | + t.setId(null); | ||
| 33 | + return (T) this.repository.save(t); | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + @Override | ||
| 37 | + public Boolean deleteByBid(Long bid) { | ||
| 38 | + return this.repository.deleteByBid(bid) > 0; | ||
| 39 | + } | ||
| 40 | +} |
sl-express-ms-transport-service/src/main/java/com/sl/transport/service/impl/TLTServiceImpl.java
0 → 100644
| 1 | +package com.sl.transport.service.impl; | ||
| 2 | + | ||
| 3 | +import com.sl.transport.entity.node.TLTEntity; | ||
| 4 | +import com.sl.transport.repository.TLTRepository; | ||
| 5 | +import com.sl.transport.service.TLTService; | ||
| 6 | +import org.springframework.stereotype.Service; | ||
| 7 | + | ||
| 8 | +@Service | ||
| 9 | +public class TLTServiceImpl extends ServiceImpl<TLTRepository, TLTEntity> implements TLTService { | ||
| 10 | +} |
sl-express-ms-transport-service/src/main/java/com/sl/transport/service/impl/TransportLineServiceImpl.java
0 → 100644
| 1 | +package com.sl.transport.service.impl; | ||
| 2 | + | ||
| 3 | +import cn.hutool.core.bean.BeanUtil; | ||
| 4 | +import cn.hutool.core.bean.copier.CopyOptions; | ||
| 5 | +import cn.hutool.core.collection.CollUtil; | ||
| 6 | +import cn.hutool.core.convert.Convert; | ||
| 7 | +import cn.hutool.core.map.MapUtil; | ||
| 8 | +import cn.hutool.core.util.NumberUtil; | ||
| 9 | +import cn.hutool.core.util.ObjectUtil; | ||
| 10 | +import cn.hutool.core.util.StrUtil; | ||
| 11 | +import cn.hutool.json.JSONObject; | ||
| 12 | +import cn.hutool.json.JSONUtil; | ||
| 13 | +import com.itheima.em.sdk.EagleMapTemplate; | ||
| 14 | +import com.itheima.em.sdk.enums.ProviderEnum; | ||
| 15 | +import com.itheima.em.sdk.vo.Coordinate; | ||
| 16 | +import com.sl.transport.common.exception.SLException; | ||
| 17 | +import com.sl.transport.common.util.PageResponse; | ||
| 18 | +import com.sl.transport.domain.DispatchConfigurationDTO; | ||
| 19 | +import com.sl.transport.domain.OrganDTO; | ||
| 20 | +import com.sl.transport.domain.TransportLineNodeDTO; | ||
| 21 | +import com.sl.transport.domain.TransportLineSearchDTO; | ||
| 22 | +import com.sl.transport.entity.line.TransportLine; | ||
| 23 | +import com.sl.transport.entity.node.AgencyEntity; | ||
| 24 | +import com.sl.transport.entity.node.BaseEntity; | ||
| 25 | +import com.sl.transport.entity.node.OLTEntity; | ||
| 26 | +import com.sl.transport.entity.node.TLTEntity; | ||
| 27 | +import com.sl.transport.enums.DispatchMethodEnum; | ||
| 28 | +import com.sl.transport.enums.ExceptionEnum; | ||
| 29 | +import com.sl.transport.enums.TransportLineEnum; | ||
| 30 | +import com.sl.transport.repository.TransportLineRepository; | ||
| 31 | +import com.sl.transport.service.CostConfigurationService; | ||
| 32 | +import com.sl.transport.service.DispatchConfigurationService; | ||
| 33 | +import com.sl.transport.service.OrganService; | ||
| 34 | +import com.sl.transport.service.TransportLineService; | ||
| 35 | +import org.checkerframework.checker.units.qual.A; | ||
| 36 | +import org.springframework.beans.factory.annotation.Autowired; | ||
| 37 | +import org.springframework.data.neo4j.core.Neo4jClient; | ||
| 38 | +import org.springframework.stereotype.Service; | ||
| 39 | + | ||
| 40 | +import javax.annotation.Resource; | ||
| 41 | +import java.util.List; | ||
| 42 | +import java.util.Map; | ||
| 43 | + | ||
| 44 | +@Service | ||
| 45 | +public class TransportLineServiceImpl implements TransportLineService { | ||
| 46 | + | ||
| 47 | + @Autowired | ||
| 48 | + private TransportLineRepository transportLineRepository; | ||
| 49 | + | ||
| 50 | + @Autowired | ||
| 51 | + private EagleMapTemplate eagleMapTemplate; | ||
| 52 | + | ||
| 53 | + @Autowired | ||
| 54 | + private OrganService organService; | ||
| 55 | + | ||
| 56 | + @Autowired | ||
| 57 | + private DispatchConfigurationService dispatchConfigurationService; | ||
| 58 | + | ||
| 59 | + @Autowired | ||
| 60 | + private CostConfigurationService costConfigurationService; | ||
| 61 | + | ||
| 62 | + @Override | ||
| 63 | + public Boolean createLine(TransportLine transportLine) { | ||
| 64 | + TransportLineEnum transportLineEnum = TransportLineEnum.codeOf(transportLine.getType()); | ||
| 65 | + if (null == transportLineEnum) { | ||
| 66 | + throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR); | ||
| 67 | + } | ||
| 68 | + | ||
| 69 | + if (ObjectUtil.equal(transportLine.getStartOrganId(), transportLine.getEndOrganId())) { | ||
| 70 | + //起点终点不能相同 | ||
| 71 | + throw new SLException(ExceptionEnum.TRANSPORT_LINE_ORGAN_CANNOT_SAME); | ||
| 72 | + } | ||
| 73 | + | ||
| 74 | + BaseEntity firstNode; | ||
| 75 | + BaseEntity secondNode; | ||
| 76 | + switch (transportLineEnum) { | ||
| 77 | + case TRUNK_LINE: { | ||
| 78 | + // 干线 | ||
| 79 | + firstNode = OLTEntity.builder().bid(transportLine.getStartOrganId()).build(); | ||
| 80 | + secondNode = OLTEntity.builder().bid(transportLine.getEndOrganId()).build(); | ||
| 81 | + break; | ||
| 82 | + } | ||
| 83 | + case BRANCH_LINE: { | ||
| 84 | + // 支线,起点必须是 二级转运中心 | ||
| 85 | + firstNode = TLTEntity.builder().bid(transportLine.getStartOrganId()).build(); | ||
| 86 | + secondNode = OLTEntity.builder().bid(transportLine.getEndOrganId()).build(); | ||
| 87 | + break; | ||
| 88 | + } | ||
| 89 | + case CONNECT_LINE: { | ||
| 90 | + // 接驳路线,起点必须是 网点 | ||
| 91 | + firstNode = AgencyEntity.builder().bid(transportLine.getStartOrganId()).build(); | ||
| 92 | + secondNode = TLTEntity.builder().bid(transportLine.getEndOrganId()).build(); | ||
| 93 | + break; | ||
| 94 | + } | ||
| 95 | + default: { | ||
| 96 | + throw new SLException(ExceptionEnum.TRANSPORT_LINE_TYPE_ERROR); | ||
| 97 | + } | ||
| 98 | + } | ||
| 99 | + | ||
| 100 | + if (ObjectUtil.hasEmpty(firstNode, secondNode)) { | ||
| 101 | + throw new SLException(ExceptionEnum.START_END_ORGAN_NOT_FOUND); | ||
| 102 | + } | ||
| 103 | + | ||
| 104 | + //判断路线是否已经存在 | ||
| 105 | + Long count = this.transportLineRepository.queryCount(firstNode, secondNode); | ||
| 106 | + if (count > 0) { | ||
| 107 | + throw new SLException(ExceptionEnum.TRANSPORT_LINE_ALREADY_EXISTS); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + transportLine.setId(null); | ||
| 111 | + transportLine.setCreated(System.currentTimeMillis()); | ||
| 112 | + transportLine.setUpdated(transportLine.getCreated()); | ||
| 113 | + //补充信息 | ||
| 114 | + this.infoFromMap(firstNode, secondNode, transportLine); | ||
| 115 | + | ||
| 116 | + count = this.transportLineRepository.create(firstNode, secondNode, transportLine); | ||
| 117 | + return count > 0; | ||
| 118 | + } | ||
| 119 | + | ||
| 120 | + /** | ||
| 121 | + * 通过地图查询距离、时间,计算成本 | ||
| 122 | + * | ||
| 123 | + * @param firstNode 开始节点 | ||
| 124 | + * @param secondNode 结束节点 | ||
| 125 | + * @param transportLine 路线对象 | ||
| 126 | + */ | ||
| 127 | + private void infoFromMap(BaseEntity firstNode, BaseEntity secondNode, TransportLine transportLine) { | ||
| 128 | + //查询节点数据 | ||
| 129 | + OrganDTO startOrgan = this.organService.findByBid(firstNode.getBid()); | ||
| 130 | + if (ObjectUtil.hasEmpty(startOrgan, startOrgan.getLongitude(), startOrgan.getLatitude())) { | ||
| 131 | + throw new SLException("请先完善机构信息"); | ||
| 132 | + } | ||
| 133 | + OrganDTO endOrgan = this.organService.findByBid(secondNode.getBid()); | ||
| 134 | + if (ObjectUtil.hasEmpty(endOrgan, endOrgan.getLongitude(), endOrgan.getLatitude())) { | ||
| 135 | + throw new SLException("请先完善机构信息"); | ||
| 136 | + } | ||
| 137 | + | ||
| 138 | + //查询地图服务商 | ||
| 139 | + Coordinate origin = new Coordinate(startOrgan.getLongitude(), startOrgan.getLatitude()); | ||
| 140 | + Coordinate destination = new Coordinate(endOrgan.getLongitude(), endOrgan.getLatitude()); | ||
| 141 | + //设置高德地图参数,默认是不返回预计耗时的,需要额外设置参数 | ||
| 142 | + Map<String, Object> param = MapUtil.<String, Object>builder().put("show_fields", "cost").build(); | ||
| 143 | + String driving = this.eagleMapTemplate.opsForDirection().driving(ProviderEnum.AMAP, origin, destination, param); | ||
| 144 | + if (StrUtil.isEmpty(driving)) { | ||
| 145 | + return; | ||
| 146 | + } | ||
| 147 | + JSONObject jsonObject = JSONUtil.parseObj(driving); | ||
| 148 | + //时间,单位:秒 | ||
| 149 | + Long duration = Convert.toLong(jsonObject.getByPath("route.paths[0].cost.duration"), -1L); | ||
| 150 | + transportLine.setTime(duration); | ||
| 151 | + //距离,单位:米 | ||
| 152 | + Double distance = Convert.toDouble(jsonObject.getByPath("route.paths[0].distance"), -1d); | ||
| 153 | + transportLine.setDistance(NumberUtil.round(distance, 0).doubleValue()); | ||
| 154 | + | ||
| 155 | + // 总成本 = 每公里平均成本 * 距离(单位:米) / 1000 | ||
| 156 | + Double cost = costConfigurationService.findCostByType(transportLine.getType()); | ||
| 157 | + transportLine.setCost(NumberUtil.round(cost * distance / 1000, 2).doubleValue()); | ||
| 158 | + } | ||
| 159 | + | ||
| 160 | + @Override | ||
| 161 | + public Boolean updateLine(TransportLine transportLine) { | ||
| 162 | + // 先查后改 | ||
| 163 | + TransportLine transportLineData = this.queryById(transportLine.getId()); | ||
| 164 | + if (null == transportLineData) { | ||
| 165 | + throw new SLException(ExceptionEnum.TRANSPORT_LINE_NOT_FOUND); | ||
| 166 | + } | ||
| 167 | + | ||
| 168 | + //拷贝数据,忽略null值以及不能修改的字段 | ||
| 169 | + BeanUtil.copyProperties(transportLine, transportLineData, CopyOptions.create().setIgnoreNullValue(true) | ||
| 170 | + .setIgnoreProperties("type", "startOrganId", "startOrganName", "endOrganId", "endOrganName")); | ||
| 171 | + | ||
| 172 | + transportLineData.setUpdated(System.currentTimeMillis()); | ||
| 173 | + Long count = this.transportLineRepository.update(transportLineData); | ||
| 174 | + return count > 0; | ||
| 175 | + } | ||
| 176 | + | ||
| 177 | + @Override | ||
| 178 | + public Boolean deleteLine(Long id) { | ||
| 179 | + Long count = this.transportLineRepository.remove(id); | ||
| 180 | + return count > 0; | ||
| 181 | + } | ||
| 182 | + | ||
| 183 | + @Override | ||
| 184 | + public PageResponse<TransportLine> queryPageList(TransportLineSearchDTO transportLineSearchDTO) { | ||
| 185 | + return this.transportLineRepository.queryPageList(transportLineSearchDTO); | ||
| 186 | + } | ||
| 187 | + | ||
| 188 | + @Override | ||
| 189 | + public TransportLineNodeDTO queryShortestPath(Long startId, Long endId) { | ||
| 190 | + AgencyEntity start = AgencyEntity.builder().bid(startId).build(); | ||
| 191 | + AgencyEntity end = AgencyEntity.builder().bid(endId).build(); | ||
| 192 | + if (ObjectUtil.hasEmpty(start, end)) { | ||
| 193 | + throw new SLException(ExceptionEnum.START_END_ORGAN_NOT_FOUND); | ||
| 194 | + } | ||
| 195 | + return this.transportLineRepository.findShortestPath(start, end); | ||
| 196 | + } | ||
| 197 | + | ||
| 198 | + @Override | ||
| 199 | + public TransportLineNodeDTO findLowestPath(Long startId, Long endId) { | ||
| 200 | + AgencyEntity start = AgencyEntity.builder().bid(startId).build(); | ||
| 201 | + AgencyEntity end = AgencyEntity.builder().bid(endId).build(); | ||
| 202 | + | ||
| 203 | + if (ObjectUtil.hasEmpty(start, end)) { | ||
| 204 | + throw new SLException(ExceptionEnum.START_END_ORGAN_NOT_FOUND); | ||
| 205 | + } | ||
| 206 | + | ||
| 207 | + List<TransportLineNodeDTO> pathList = this.transportLineRepository.findPathList(start, end, 10, 1); | ||
| 208 | + if (CollUtil.isNotEmpty(pathList)) { | ||
| 209 | + return pathList.get(0); | ||
| 210 | + } | ||
| 211 | + return null; | ||
| 212 | + } | ||
| 213 | + | ||
| 214 | + @Override | ||
| 215 | + public TransportLineNodeDTO queryPathByDispatchMethod(Long startId, Long endId) { | ||
| 216 | + //调度方式配置 | ||
| 217 | + DispatchConfigurationDTO configuration = this.dispatchConfigurationService.findConfiguration(); | ||
| 218 | + int method = configuration.getDispatchMethod(); | ||
| 219 | + | ||
| 220 | + //调度方式,1转运次数最少,2成本最低 | ||
| 221 | + if (ObjectUtil.equal(DispatchMethodEnum.SHORTEST_PATH.getCode(), method)) { | ||
| 222 | + return this.queryShortestPath(startId, endId); | ||
| 223 | + } else { | ||
| 224 | + return this.findLowestPath(startId, endId); | ||
| 225 | + } | ||
| 226 | + } | ||
| 227 | + | ||
| 228 | + @Override | ||
| 229 | + public List<TransportLine> queryByIds(Long... ids) { | ||
| 230 | + return this.transportLineRepository.queryByIds(ids); | ||
| 231 | + } | ||
| 232 | + | ||
| 233 | + @Override | ||
| 234 | + public TransportLine queryById(Long id) { | ||
| 235 | + return this.transportLineRepository.queryById(id); | ||
| 236 | + } | ||
| 237 | +} |