Commit 59c1b1517668e6c78d8eaaaca7c172e1dbd66bc5

Authored by shuhongfan
1 parent 30db74bf

day06-路线规划之微服务

.gitignore
... ... @@ -16,3 +16,4 @@
16 16 *.iml
17 17 out
18 18 gen
  19 +/.idea/
... ...
.idea/compiler.xml
... ... @@ -141,6 +141,8 @@
141 141 <entry name="$MAVEN_REPOSITORY$/org/jsoup/jsoup/1.12.1/jsoup-1.12.1.jar" />
142 142 <entry name="$MAVEN_REPOSITORY$/com/github/javaparser/javaparser-core/3.14.10/javaparser-core-3.14.10.jar" />
143 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 146 <entry name="$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter/5.6.2/junit-jupiter-5.6.2.jar" />
145 147 <entry name="$MAVEN_REPOSITORY$/org/junit/jupiter/junit-jupiter-api/5.6.2/junit-jupiter-api-5.6.2.jar" />
146 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 64 <file url="file://$PROJECT_DIR$/sentinel/sentinel-core/src/main/java" charset="UTF-8" />
65 65 <file url="file://$PROJECT_DIR$/sentinel/sentinel-core/src/main/resources" charset="UTF-8" />
66 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 69 <file url="file://$PROJECT_DIR$/sentinel/sentinel-demo/sentinel-demo-annotation-cdi-interceptor/src/main/java" charset="UTF-8" />
68 70 <file url="file://$PROJECT_DIR$/sentinel/sentinel-demo/sentinel-demo-annotation-cdi-interceptor/src/main/resources" charset="UTF-8" />
69 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 2 <module type="JAVA_MODULE" version="4">
3 3 <component name="NewModuleRootManager" inherit-compiler-output="true">
4 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 9 <orderEntry type="inheritedJdk" />
7 10 <orderEntry type="sourceFolder" forTests="false" />
8 11 </component>
... ...
03-资料/maven/settings.xml
... ... @@ -4,10 +4,10 @@
4 4 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
5 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 11 <servers>
12 12 <server>
13 13 <id>sl-releases</id>
... ... @@ -21,7 +21,7 @@
21 21 </server>
22 22 </servers>
23 23  
24   - <!-- 使用阿里云maven镜像,排除私服资源库 -->
  24 + <!-- 使锟矫帮拷锟斤拷锟斤拷maven锟斤拷锟斤拷锟脚筹拷私锟斤拷锟斤拷源锟斤拷 -->
25 25 <mirrors>
26 26 <mirror>
27 27 <id>mirror</id>
... ... @@ -34,7 +34,7 @@
34 34 <profiles>
35 35 <profile>
36 36 <id>sl</id>
37   - <!-- 配置项目deploy的地址 -->
  37 + <!-- 锟斤拷锟斤拷锟斤拷目deploy锟侥碉拷址 -->
38 38 <properties>
39 39 <altReleaseDeploymentRepository>
40 40 sl-releases::default::http://maven.sl-express.com/nexus/content/repositories/releases/
... ... @@ -43,7 +43,7 @@
43 43 sl-snapshots::default::http://maven.sl-express.com/nexus/content/repositories/snapshots/
44 44 </altSnapshotDeploymentRepository>
45 45 </properties>
46   - <!-- 配置项目下载依赖的私服地址 -->
  46 + <!-- 锟斤拷锟斤拷锟斤拷目锟斤拷锟斤拷锟斤拷锟斤拷锟斤拷私锟斤拷锟斤拷址 -->
47 47 <repositories>
48 48 <repository>
49 49 <id>sl-releases</id>
... ... @@ -70,7 +70,7 @@
70 70 </profiles>
71 71  
72 72 <activeProfiles>
73   - <!-- 激活配置 -->
  73 + <!-- 锟斤拷锟斤拷锟斤拷锟斤拷 -->
74 74 <activeProfile>sl</activeProfile>
75 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 16 TRANSPORT_LINE_ALREADY_EXISTS(1003, "路线已经存在"),
17 17 TRANSPORT_LINE_NOT_FOUND(1004, "路线不存在"),
18 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 22 private Integer code;
22 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 */
24 24 @Service
25 25 public class CostConfigurationServiceImpl implements CostConfigurationService {
26   -
27   - @Resource
28   - private StringRedisTemplate stringRedisTemplate;
29   -
30 26 /**
31 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 35 TransportLineEnum.TRUNK_LINE.getCode(), 0.8,
40 36 TransportLineEnum.BRANCH_LINE.getCode(), 1.2,
41 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 +}
... ...