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

Spring Cloud微服务项目完整搭建指南

好的,这是一个非常经典和完整的微服务实践问题。我将为您提供一个从零开始、保姆级的教程,一步步搭建一个包含用户服务(user-service)和问答服务(qa-service)的 Spring Cloud 项目。

我们将使用以下技术栈:

  • 构建工具: Maven

  • 开发环境: JDK 17+ (Spring Boot 3.x 要求)

  • Spring Boot: 3.2.5

  • Spring Cloud: 2023.0.1

  • 服务注册与发现: Eureka

  • 配置中心: Spring Cloud Config

  • 数据库: MySQL (使用 Spring Data JPA)

  • 服务间通信: OpenFeign

整个教程分为以下几个大步骤,请严格按照顺序执行:

  1. 环境准备

  2. 项目整体结构与父工程搭建

  3. 搭建服务注册中心 (Eureka Server)

  4. 搭建配置中心 (Config Server)

  5. 创建配置中心的 Git 仓库

  6. 搭建用户服务 (user-service)

  7. 搭建问答服务 (qa-service)

  8. 启动与测试整个系统


第 1 步:环境准备

  1. 安装 JDK 17 或更高版本

  2. 安装 Maven

  3. 安装 Git

  4. 安装 Docker (推荐,用于快速启动 MySQL 数据库)。

  5. 安装一个 IDE,如 IntelliJ IDEA 或 VS Code。

启动 MySQL 数据库 打开终端,运行以下 Docker 命令来启动一个 MySQL 8.0 实例。

Bash

docker run -d --name mysql-for-sc -p 3306:3306 -e MYSQL_ROOT_PASSWORD=root -e MYSQL_DATABASE=user_db -e MYSQL_DATABASE=qa_db mysql:8.0

这会创建一个名为 mysql-for-sc 的容器,暴露 3306 端口,并创建两个我们稍后会用到的数据库:user_dbqa_db


第 2 步:项目整体结构与父工程搭建

我们将创建一个父项目 spring-cloud-tutorial 来管理所有子模块的依赖和版本。

2.1 最终目录结构

spring-cloud-tutorial/
├── .gitignore
├── pom.xml                   # 父POM,管理所有依赖版本
├── eureka-server/            # 服务注册中心
│   └── ...
├── config-server/            # 配置中心
│   └── ...
├── user-service/             # 用户服务
│   └── ...
└── qa-service/               # 问答服务└── ...

2.2 创建父项目

  1. 创建一个名为 spring-cloud-tutorial 的空文件夹。

  2. 在文件夹中创建一个 pom.xml 文件,内容如下。这个文件至关重要,它定义了 Spring Boot 和 Spring Cloud 的版本,并统一管理所有子模块的依赖。

spring-cloud-tutorial/pom.xml

XML

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.example</groupId><artifactId>spring-cloud-tutorial</artifactId><version>1.0.0</version><packaging>pom</packaging> <modules><module>eureka-server</module><module>config-server</module><module>user-service</module><module>qa-service</module></modules><properties><java.version>17</java.version><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><spring-boot.version>3.2.5</spring-boot.version><spring-cloud.version>2023.0.1</spring-cloud.version></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>${spring-boot.version}</version><type>pom</type><scope>import</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-dependencies</artifactId><version>${spring-cloud.version}</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId><version>${spring-boot.version}</version><executions><execution><goals><goal>repackage</goal></goals></execution></executions></plugin></plugins></build>
</project>

第 3 步:搭建服务注册中心 (Eureka Server)

Eureka 是服务“管理员”,所有服务启动后都来这里“报到”(注册),其他服务可以从这里找到它们。

3.1 创建 eureka-server 模块

spring-cloud-tutorial 目录下创建一个 eureka-server 子模块(一个标准的 Spring Boot 项目)。

3.2 目录结构

eureka-server/
├── pom.xml
└── src/└── main/├── java/│   └── com/│       └── example/│           └── eurekaserver/│               └── EurekaServerApplication.java└── resources/└── application.yml

3.3 pom.xml

XML

<?xml version="1.0" encoding="UTF-8"?>
<project ...><modelVersion>4.0.0</modelVersion><parent><groupId>com.example</groupId><artifactId>spring-cloud-tutorial</artifactId><version>1.0.0</version><relativePath>../pom.xml</relativePath></parent><artifactId>eureka-server</artifactId><name>eureka-server</name><description>Service Registry Center</description><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-server</artifactId></dependency></dependencies>
</project>

3.4 启动类

@EnableEurekaServer 注解声明这是一个 Eureka 服务注册中心。

EurekaServerApplication.java

Java

package com.example.eurekaserver;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;@SpringBootApplication
@EnableEurekaServer
public class EurekaServerApplication {public static void main(String[] args) {SpringApplication.run(EurekaServerApplication.class, args);}
}

3.5 配置文件

application.yml

YAML

server:port: 8761 # Eureka 默认端口eureka:instance:hostname: localhostclient:# Eureka Server 也是一个客户端,但我们不希望它注册自己register-with-eureka: false# 也不需要从其他注册中心获取服务列表fetch-registry: falseservice-url:# 单机模式下,指向自己defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka/

第 4 步:搭建配置中心 (Config Server)

Config Server 用于集中管理所有微服务的配置文件。

4.1 创建 config-server 模块

spring-cloud-tutorial 目录下创建 config-server 子模块。

4.2 目录结构

config-server/
├── pom.xml
└── src/└── main/├── java/│   └── com/│       └── example/│           └── configserver/│               └── ConfigServerApplication.java└── resources/└── application.yml

4.3 pom.xml

XML

<?xml version="1.0" encoding="UTF-8"?>
<project ...><modelVersion>4.0.0</modelVersion><parent><groupId>com.example</groupId><artifactId>spring-cloud-tutorial</artifactId><version>1.0.0</version><relativePath>../pom.xml</relativePath></parent><artifactId>config-server</artifactId><name>config-server</name><description>Centralized Configuration Server</description><dependencies><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-config-server</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency></dependencies>
</project>

4.4 启动类

@EnableConfigServer 注解声明这是一个配置中心。

ConfigServerApplication.java

Java

package com.example.configserver;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.config.server.EnableConfigServer;@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {public static void main(String[] args) {SpringApplication.run(ConfigServerApplication.class, args);}
}

4.5 配置文件

application.yml

YAML

server:port: 8888 # Config Server 默认端口spring:application:name: config-server # 服务名称cloud:config:server:git:# IMPORTANT: 替换成你自己的 Git 仓库地址uri: https://github.com/YOUR_USERNAME/spring-cloud-configs.git# 如果是本地仓库,可以使用 file:///path/to/your/repo# uri: file:///Users/yourname/path/to/spring-cloud-configsdefault-label: main # Git 分支# 如果仓库是私有的,需要配置 username 和 password# username: your-git-username# password: your-git-password# 将自己注册到 Eureka
eureka:client:service-url:defaultZone: http://localhost:8761/eureka/

第 5 步:创建配置中心的 Git 仓库

这是所有微服务配置文件的存放地。

  1. 在 GitHub, GitLab 或本地创建一个 Git 仓库 (例如 spring-cloud-configs)。

  2. 在仓库中创建以下几个文件:

user-service.yml

YAML

server:port: 8081 # 用户服务端口# 数据库配置
spring:datasource:url: jdbc:mysql://localhost:3306/user_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTCusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driverjpa:hibernate:ddl-auto: update # 自动更新表结构show-sql: true # 显示 SQL# Eureka 配置
eureka:instance:prefer-ip-address: true # 优先使用 IP 地址注册client:service-url:defaultZone: http://localhost:8761/eureka/# 暴露所有 actuator 端点以供监控
management:endpoints:web:exposure:include: "*"

qa-service.yml

YAML

server:port: 8082 # 问答服务端口# 数据库配置
spring:datasource:url: jdbc:mysql://localhost:3306/qa_db?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTCusername: rootpassword: rootdriver-class-name: com.mysql.cj.jdbc.Driverjpa:hibernate:ddl-auto: updateshow-sql: true# Eureka 配置
eureka:instance:prefer-ip-address: trueclient:service-url:defaultZone: http://localhost:8761/eureka/# 暴露所有 actuator 端点
management:endpoints:web:exposure:include: "*"# Feign 配置
feign:client:config:default:connect-timeout: 5000 # 连接超时时间read-timeout: 5000 # 读取超时时间
  1. 将这些文件 commit 并 push 到你的 Git 仓库。确保 config-serverapplication.yml 中的 uri 指向这个仓库


第 6 步:搭建用户服务 (user-service)

6.1 创建 user-service 模块

6.2 目录结构

user-service/
├── pom.xml
└── src/└── main/├── java/│   └── com/│       └── example/│           └── userservice/│               ├── controller/│               │   └── UserController.java│               ├── entity/│               │   └── User.java│               ├── repository/│               │   └── UserRepository.java│               └── UserSerivceApplication.java└── resources/├── bootstrap.yml  # 关键:用于连接 Config Server└── application.yml # 可以为空,或放一些不常变的本地配置

6.3 pom.xml

XML

<?xml version="1.0" encoding="UTF-8"?>
<project ...><modelVersion>4.0.0</modelVersion><parent><groupId>com.example</groupId><artifactId>spring-cloud-tutorial</artifactId><version>1.0.0</version><relativePath>../pom.xml</relativePath></parent><artifactId>user-service</artifactId><name>user-service</name><description>User Service</description><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency></dependencies>
</project>

6.4 bootstrap.yml

这个文件是关键。它的加载优先级高于 application.yml,用于告诉服务去哪里找配置中心。

src/main/resources/bootstrap.yml

YAML

spring:application:# 这个名字必须和 Git 仓库里的配置文件名 (user-service.yml) 对应name: user-servicecloud:config:# 配置中心地址uri: http://localhost:8888# 使用的分支label: main

application.yml 可以留空,因为所有配置都将从 Config Server 加载。

6.5 Java 代码

Entity (User.java) 注意:Spring Boot 3 使用 jakarta.persistence 而不是 javax.persistence

Java

package com.example.userservice.entity;import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;
import jakarta.persistence.Table;@Entity
@Table(name = "users") // 'user' is a reserved keyword in some DBs
public class User {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String username;private String email;// Getters and Setters...
}

Repository (UserRepository.java)

Java

package com.example.userservice.repository;import com.example.userservice.entity.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;@Repository
public interface UserRepository extends JpaRepository<User, Long> {
}

Controller (UserController.java)

Java

package com.example.userservice.controller;import com.example.userservice.entity.User;
import com.example.userservice.repository.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;import java.util.List;@RestController
@RequestMapping("/users")
public class UserController {@Autowiredprivate UserRepository userRepository;@PostMappingpublic User createUser(@RequestBody User user) {return userRepository.save(user);}@GetMapping("/{id}")public ResponseEntity<User> getUserById(@PathVariable Long id) {return userRepository.findById(id).map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());}@GetMappingpublic List<User> getAllUsers() {return userRepository.findAll();}
}

Application (UserServiceApplication.java)

Java

package com.example.userservice;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;@SpringBootApplication
public class UserServiceApplication {public static void main(String[] args) {SpringApplication.run(UserServiceApplication.class, args);}
}

第 7 步:搭建问答服务 (qa-service)

此服务将通过 Feign 调用 user-service

7.1 创建 qa-service 模块

7.2 目录结构

qa-service/
├── pom.xml
└── src/└── main/├── java/│   └── com/│       └── example/│           └── qaservice/│               ├── client/          # Feign Client 接口│               │   └── UserClient.java│               ├── controller/│               │   └── QuestionController.java│               ├── dto/             # 数据传输对象│               │   ├── QuestionDTO.java│               │   └── UserDTO.java│               ├── entity/│               │   └── Question.java│               ├── repository/│               │   └── QuestionRepository.java│               └── QaServiceApplication.java└── resources/└── bootstrap.yml

7.3 pom.xml

XML

<?xml version="1.0" encoding="UTF-8"?>
<project ...><modelVersion>4.0.0</modelVersion><parent><groupId>com.example</groupId><artifactId>spring-cloud-tutorial</artifactId><version>1.0.0</version><relativePath>../pom.xml</relativePath></parent><artifactId>qa-service</artifactId><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-jpa</artifactId></dependency><dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId><scope>runtime</scope></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-netflix-eureka-client</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-config</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-bootstrap</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-actuator</artifactId></dependency><dependency><groupId>org.springframework.cloud</groupId><artifactId>spring-cloud-starter-openfeign</artifactId></dependency></dependencies>
</project>

7.4 bootstrap.yml

src/main/resources/bootstrap.yml

YAML

spring:application:name: qa-service # 对应 qa-service.ymlcloud:config:uri: http://localhost:8888label: main

7.5 Java 代码

Entity (Question.java)

Java

package com.example.qaservice.entity;import jakarta.persistence.*;@Entity
@Table(name = "questions")
public class Question {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String title;private String content;private Long authorId; // 提问者的用户ID// Getters and Setters...
}

Repository (QuestionRepository.java)

Java

package com.example.qaservice.repository;import com.example.qaservice.entity.Question;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;@Repository
public interface QuestionRepository extends JpaRepository<Question, Long> {
}

DTOs (数据传输对象) 创建一个 UserDTO 来接收来自 user-service 的数据。

Java

// package com.example.qaservice.dto;
public class UserDTO {private Long id;private String username;private String email;// Getters and Setters...
}

创建一个 QuestionDTO 来组合问题和作者信息。

Java

// package com.example.qaservice.dto;
public class QuestionDTO {private Long id;private String title;private String content;private UserDTO author; // 作者信息// Getters and Setters...
}

Feign Client (UserClient.java) 这是 Feign 的核心,定义一个接口来声明式地调用远程服务。

Java

package com.example.qaservice.client;import com.example.qaservice.dto.UserDTO;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;// name = "user-service" 必须是用户服务在 Eureka 上注册的服务名
@FeignClient(name = "user-service")
public interface UserClient {// 路径和方法签名必须和 user-service 的 Controller 完全匹配@GetMapping("/users/{id}")UserDTO getUserById(@PathVariable("id") Long id);
}

Controller (QuestionController.java)

Java

package com.example.qaservice.controller;import com.example.qaservice.client.UserClient;
import com.example.qaservice.dto.QuestionDTO;
import com.example.qaservice.dto.UserDTO;
import com.example.qaservice.entity.Question;
import com.example.qaservice.repository.QuestionRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/questions")
public class QuestionController {@Autowiredprivate QuestionRepository questionRepository;@Autowiredprivate UserClient userClient; // 注入 Feign Client@PostMappingpublic Question createQuestion(@RequestBody Question question) {return questionRepository.save(question);}@GetMapping("/{id}")public ResponseEntity<QuestionDTO> getQuestionWithAuthor(@PathVariable Long id) {return questionRepository.findById(id).map(question -> {// 通过 Feign 调用 user-service 获取作者信息UserDTO author = userClient.getUserById(question.getAuthorId());// 组装 DTOQuestionDTO dto = new QuestionDTO();dto.setId(question.getId());dto.setTitle(question.getTitle());dto.setContent(question.getContent());dto.setAuthor(author);return ResponseEntity.ok(dto);}).orElse(ResponseEntity.notFound().build());}
}

Application (QaServiceApplication.java) 使用 @EnableFeignClients 开启 Feign 功能。

Java

package com.example.qaservice;import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;@SpringBootApplication
@EnableFeignClients // 开启 Feign
public class QaServiceApplication {public static void main(String[] args) {SpringApplication.run(QaServiceApplication.class, args);}
}

第 8 步:启动与测试整个系统

8.1 启动顺序

必须严格按照以下顺序启动,否则会因依赖服务未就绪而失败!

  1. 启动 MySQL: docker start mysql-for-sc (如果已在第一步启动,则跳过)

  2. 启动 eureka-server: 运行 EurekaServerApplication

    • 启动后,访问 http://localhost:8761。你应该能看到 Eureka 的管理界面,目前 "Instances currently registered with Eureka" 下是空的。

  3. 启动 config-server: 运行 ConfigServerApplication

    • 启动后,刷新 Eureka 界面 (http://localhost:8761),你应该能看到 CONFIG-SERVER 已经注册上来了。

    • 你也可以测试 Config Server 是否正常工作,访问 http://localhost:8888/user-service/main,应该能看到 user-service.yml 的配置内容。

  4. 启动 user-service: 运行 UserServiceApplication

    • 启动后,刷新 Eureka 界面,你应该能看到 USER-SERVICE 也注册上来了。

  5. 启动 qa-service: 运行 QaServiceApplication

    • 启动后,刷新 Eureka 界面,你应该能看到 QA-SERVICE 也注册上来了。

8.2 功能测试 (使用 curl 或 Postman)

  1. 创建一个用户 (调用 user-service)

    Bash

    curl -X POST http://localhost:8081/users \
    -H "Content-Type: application/json" \
    -d '{"username": "Alice", "email": "alice@example.com"}'
    

    你会得到类似 {"id":1,"username":"Alice","email":"alice@example.com"} 的返回。记下这个 id (这里是 1)。

  2. 验证用户创建成功 (调用 user-service)

    Bash

    curl http://localhost:8081/users/1
    
  3. 创建一个问题 (调用 qa-service) 这个问题的作者是刚才创建的用户 (id=1)。

    Bash

    curl -X POST http://localhost:8082/questions \
    -H "Content-Type: application/json" \
    -d '{"title": "What is Spring Cloud?", "content": "Can someone explain Spring Cloud in simple terms?", "authorId": 1}'
    

    你会得到问题创建成功的返回,记下问题的 id (这里假设也是 1)。

  4. 测试 Feign 调用 (关键步骤) 现在,我们请求 qa-service 获取问题详情。qa-service 内部会自动调用 user-service 来获取作者信息。

    Bash

    curl http://localhost:8082/questions/1
    

    如果一切正常,你会得到一个包含了用户信息的完整响应:

    JSON

    {"id": 1,"title": "What is Spring Cloud?","content": "Can someone explain Spring Cloud in simple terms?","author": {"id": 1,"username": "Alice","email": "alice@example.com"}
    }
    

    看到这个结果,恭喜你,整个系统已经成功跑起来了!你已经搭建了一个包含服务注册、配置中心、数据库交互、服务间通信的完整 Spring Cloud 微服务项目。

http://www.dtcms.com/a/297837.html

相关文章:

  • ODFM(正交频分复用)系统中加入汉明码(Hamming Code)的主要目的是增强抗误码能力,通过**前向纠错(FEC)**机制提高传输可靠性
  • 详解FreeRTOS开发过程(八)-- 时间标志
  • 相机ROI 参数
  • 【飞控】在 Windows 中为PX4自动驾驶仪安装 UAV 工具箱支持包
  • Python 程序设计讲义(19):选择结构程序设计
  • 架构篇(一):告别MVC/MVP,为何“组件化”是现代前端的唯一答案?
  • [2025CVPR-图象分类方向]CATANet:用于轻量级图像超分辨率的高效内容感知标记聚合
  • Git常用命令赏析
  • Spring Boot 优雅实现多租户架构!
  • 谁将统治AI游戏时代?腾讯、网易、米哈游技术暗战
  • 基于Android的2048休闲益智游戏App
  • 上位机程序开发基础介绍
  • 大型微服务项目:听书——11 Redisson分布式布隆过滤器+Redisson分布式锁改造专辑详情接口
  • HTML5武汉旅游网站源码
  • ZedGraph 可选定轴 通过鼠标移动或通过滚轮设置轴的范围
  • linux-开机启动流程
  • 解密国密 SSL 证书:SM2、SM3、SM4 算法的协同安全效应
  • 物联网技术:起源、发展、重点技术、应用场景与未来演进
  • [RPA] Excel中的字典处理
  • Y1第4课题解(A~E)
  • Kubernetes深度解析:企业级容器编排平台的核心实践
  • 在OpenMP中,#pragma omp的使用
  • JAVA_FourTEEN_常见算法
  • Python爬虫实战:研究flanker相关技术
  • 通过 Web3 区块链安全评估,领先应对网络威胁
  • Java零基础入门学习知识点2-JDK安装配置+Maven
  • k8s常用基础命令总结
  • P1106 删数问题 - 洛谷
  • 深度学习day02--神经网络(前三节)
  • 使用 Dijkstra 算法 和 旅行商问题(TSP) 规划快递员配送路线(python)