Spring Boot 微服务架构设计与实现
Spring Boot 微服务架构设计涉及微服务定义、Spring Cloud Eureka 集成、配置管理(Config)、服务间通信(Ribbon)及实际应用场景。通过构建服务注册中心、提供者与消费者,实现独立部署与网络通信,提升系统可扩展性与可维护性。

Spring Boot 微服务架构设计涉及微服务定义、Spring Cloud Eureka 集成、配置管理(Config)、服务间通信(Ribbon)及实际应用场景。通过构建服务注册中心、提供者与消费者,实现独立部署与网络通信,提升系统可扩展性与可维护性。

定义:微服务架构是一种软件架构风格,将应用程序拆分为一组独立的服务,每个服务运行在自己的进程中,通过网络进行通信。 作用:
常见的微服务架构:
特点:
步骤:
示例: 服务注册中心(Eureka Server)的 pom.xml 文件中的依赖:
<dependencies>
<!-- Eureka Server 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
服务注册中心(Eureka Server)的 application.properties 文件中的配置:
# 服务器端口
server.port=8761
# Eureka Server 配置
eureka.client.register-with-eureka=false
eureka.client.fetch-registry=false
eureka.instance.hostname=localhost
服务注册中心(Eureka Server)的启动类:
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);
}
}
服务提供者(Product Service)的 pom.xml 文件中的依赖:
<dependencies>
<!-- Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Eureka Client 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
服务提供者(Product Service)的 application.properties 文件中的配置:
# 服务器端口
server.port=8081
# 应用名称
spring.application.name=product-service
# Eureka Client 配置
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.instance.prefer-ip-address=true
服务提供者(Product Service)的实体类:
public class Product {
private Long id;
private String productId;
private String productName;
private double price;
private int sales;
public Product() {}
public Product(Long id, String productId, String productName, double price, int sales) {
this.id = id;
this.productId = productId;
this.productName = productName;
this.price = price;
this.sales = sales;
}
// Getter 和 Setter 方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getProductId() { return productId; }
public void setProductId(String productId) { this.productId = productId; }
public String getProductName() { return productName; }
public void setProductName(String productName) { this.productName = productName; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public int getSales() { return sales; }
public void setSales(int sales) { this.sales = sales; }
@Override
public String toString() {
return "Product{" +
"id=" + id +
", productId='" + productId + '\'' +
", productName='" + productName + '\'' +
", price=" + price +
", sales=" + sales +
'}';
}
}
服务提供者(Product Service)的控制器类:
import org.springframework.web.bind.annotation.*;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/products")
public class ProductController {
private List<Product> products = new ArrayList<>();
public ProductController() {
products.add(new Product(1L, "P001", "手机", 1000.0, 100));
products.add(new Product(2L, "P002", "电脑", 5000.0, 50));
products.add(new Product(3L, "P003", "电视", 3000.0, 80));
products.add(new Product(4L, "P004", "手表", 500.0, 200));
products.add(new Product(5L, "P005", "耳机", 300.0, 150));
}
@GetMapping("/")
public List<Product> getAllProducts() {
return products;
}
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return products.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);
}
@PostMapping("/")
public Product addProduct(@RequestBody Product product) {
product.setId((long) (products.size() + 1));
products.add(product);
return product;
}
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody Product product) {
Product existingProduct = getProductById(id);
if (existingProduct != null) {
existingProduct.setProductId(product.getProductId());
existingProduct.setProductName(product.getProductName());
existingProduct.setPrice(product.getPrice());
existingProduct.setSales(product.getSales());
}
return existingProduct;
}
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable Long id) {
products.removeIf(product -> product.getId().equals(id));
}
}
服务提供者(Product Service)的启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
服务消费者(Order Service)的 pom.xml 文件中的依赖:
<dependencies>
<!-- Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Eureka Client 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<!-- Ribbon 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-ribbon</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
服务消费者(Order Service)的 application.properties 文件中的配置:
# 服务器端口
server.port=8082
# 应用名称
spring.application.name=order-service
# Eureka Client 配置
eureka.client.service-url.defaultZone=http://localhost:8761/eureka/
eureka.instance.prefer-ip-address=true
服务消费者(Order Service)的实体类:
public class Product {
private Long id;
private String productId;
private String productName;
private double price;
private int sales;
public Product() {}
public Product(Long id, String productId, String productName, double price, int sales) {
this.id = id;
this.productId = productId;
this.productName = productName;
this.price = price;
this.sales = sales;
}
// Getter 和 Setter 方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getProductId() { return productId; }
public void setProductId(String productId) { this.productId = productId; }
public String getProductName() { return productName; }
public void setProductName(String productName) { this.productName = productName; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public int getSales() { return sales; }
public void setSales(int sales) { this.sales = sales; }
@Override
public String toString() {
return "Product{" +
"id=" + id +
", productId='" + productId + '\'' +
", productName='" + productName + '\'' +
", price=" + price +
", sales=" + sales +
'}';
}
}
public class Order {
private Long id;
private String orderId;
private List<Product> products;
public Order() {}
public Order(Long id, String orderId, List<Product> products) {
this.id = id;
this.orderId = orderId;
this.products = products;
}
// Getter 和 Setter 方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getOrderId() { return orderId; }
public void setOrderId(String orderId) { this.orderId = orderId; }
public List<Product> getProducts() { return products; }
public void setProducts(List<Product> products) { this.products = products; }
@Override
public String toString() {
return "Order{" +
"id=" + id +
", orderId='" + orderId + '\'' +
", products=" + products +
'}';
}
}
服务消费者(Order Service)的控制器类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
private List<Order> orders = new ArrayList<>();
public OrderController() {
orders.add(new Order(1L, "O001", new ArrayList<>()));
orders.add(new Order(2L, "O002", new ArrayList<>()));
orders.add(new Order(3L, "O003", new ArrayList<>()));
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/")
public List<Order> getAllOrders() {
return orders;
}
@GetMapping("/{id}")
public Order getOrderById(@PathVariable Long id) {
return orders.stream().filter(order -> order.getId().equals(id)).findFirst().orElse(null);
}
@PostMapping("/")
public Order addOrder(@RequestBody Order order) {
order.setId((long) (orders.size() + 1));
orders.add(order);
return order;
}
@PutMapping("/{id}")
public Order updateOrder(@PathVariable Long id, @RequestBody Order order) {
Order existingOrder = getOrderById(id);
if (existingOrder != null) {
existingOrder.setOrderId(order.getOrderId());
existingOrder.setProducts(order.getProducts());
}
return existingOrder;
}
@DeleteMapping("/{id}")
public void deleteOrder(@PathVariable Long id) {
orders.removeIf(order -> order.getId().equals(id));
}
@GetMapping("/{id}/products")
public List<Product> getOrderProducts(@PathVariable Long id) {
Order order = getOrderById(id);
if (order != null) {
List<Product> products = order.getProducts();
return products;
}
return new ArrayList<>();
}
@PostMapping("/{id}/products")
public Order addOrderProduct(@PathVariable Long id, @RequestBody Product product) {
Order order = getOrderById(id);
if (order != null) {
order.getProducts().add(product);
}
return order;
}
@DeleteMapping("/{id}/products/{productId}")
public Order deleteOrderProduct(@PathVariable Long id, @PathVariable Long productId) {
Order order = getOrderById(id);
if (order != null) {
order.getProducts().removeIf(product -> product.getId().equals(productId));
}
return order;
}
@GetMapping("/{id}/product/{productId}")
public Product getProductById(@PathVariable Long id, @PathVariable Long productId) {
Order order = getOrderById(id);
if (order != null) {
List<Product> products = order.getProducts();
return products.stream().filter(product -> product.getId().equals(productId)).findFirst().orElse(null);
}
return null;
}
}
服务消费者(Order Service)的启动类:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
@SpringBootApplication
@EnableEurekaClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
测试类:
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderServiceApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {}
@Test
void testGetAllOrders() {
List<Order> orders = restTemplate.getForObject("http://localhost:" + port + "/api/orders/", List.class);
assertThat(orders).isNotNull();
assertThat(orders.size()).isGreaterThanOrEqualTo(3);
}
@Test
void testAddOrder() {
Order order = new Order(null, "O004", new ArrayList<>());
Order savedOrder = restTemplate.postForObject("http://localhost:" + port + "/api/orders/", order, Order.class);
assertThat(savedOrder).isNotNull();
assertThat(savedOrder.getOrderId()).isEqualTo("O004");
}
@Test
void testAddOrderProduct() {
Product product = new Product(1L, "P001", "手机", 1000.0, 100);
HttpEntity<Product> requestEntity = new HttpEntity<>(product);
ResponseEntity<Order> response = restTemplate.exchange("http://localhost:" + port + "/api/orders/1/products", HttpMethod.POST, requestEntity, Order.class);
assertThat(response.getStatusCodeValue()).isEqualTo(200);
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getProducts().size()).isGreaterThanOrEqualTo(1);
}
}
步骤:
示例: 配置服务器(Config Server)的 pom.xml 文件中的依赖:
<dependencies>
<!-- Config Server 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
配置服务器(Config Server)的 application.properties 文件中的配置:
# 服务器端口
server.port=8888
# 配置服务器配置
spring.cloud.config.server.git.uri=https://github.com/username/config-repo
spring.cloud.config.server.git.search-paths=config-repo
spring.cloud.config.server.git.username=username
spring.cloud.config.server.git.password=password
配置服务器(Config Server)的启动类:
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);
}
}
配置客户端(Product Service)的 pom.xml 文件中的依赖:
<dependencies>
<!-- Web 依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- Config Client 依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<!-- 测试依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Hoxton.SR12</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
配置客户端(Product Service)的 bootstrap.properties 文件中的配置:
# 应用名称
spring.application.name=product-service
# 配置服务器地址
spring.cloud.config.uri=http://localhost:8888
配置客户端(Product Service)的 application.properties 文件中的配置:
# 服务器端口
server.port=8081
配置文件(product-service-dev.properties):
# 应用名称
spring.application.name=product-service
# 服务器端口
server.port=8081
# 数据库连接信息
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=password
# JPA 配置
spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
# H2 数据库控制台
spring.h2.console.enabled=true
spring.h2.console.path=/h2-console
作用:
示例: 服务消费者(Order Service)的控制器类:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.context.annotation.Bean;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@RestController
@RequestMapping("/api/orders")
public class OrderController {
@Autowired
private RestTemplate restTemplate;
private List<Order> orders = new ArrayList<>();
public OrderController() {
orders.add(new Order(1L, "O001", new ArrayList<>()));
orders.add(new Order(2L, "O002", new ArrayList<>()));
orders.add(new Order(3L, "O003", new ArrayList<>()));
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/")
public List<Order> getAllOrders() {
return orders;
}
@GetMapping("/{id}")
public Order getOrderById(@PathVariable Long id) {
return orders.stream().filter(order -> order.getId().equals(id)).findFirst().orElse(null);
}
@PostMapping("/")
public Order addOrder(@RequestBody Order order) {
order.setId((long) (orders.size() + 1));
orders.add(order);
return order;
}
@PutMapping("/{id}")
public Order updateOrder(@PathVariable Long id, @RequestBody Order order) {
Order existingOrder = getOrderById(id);
if (existingOrder != null) {
existingOrder.setOrderId(order.getOrderId());
existingOrder.setProducts(order.getProducts());
}
return existingOrder;
}
@DeleteMapping("/{id}")
public void deleteOrder(@PathVariable Long id) {
orders.removeIf(order -> order.getId().equals(id));
}
@GetMapping("/{id}/products")
public List<Product> getOrderProducts(@PathVariable Long id) {
Order order = getOrderById(id);
if (order != null) {
List<Product> products = order.getProducts();
return products;
}
return new ArrayList<>();
}
@PostMapping("/{id}/products")
public Order addOrderProduct(@PathVariable Long id, @RequestBody Product product) {
Order order = getOrderById(id);
if (order != null) {
order.getProducts().add(product);
}
return order;
}
@DeleteMapping("/{id}/products/{productId}")
public Order deleteOrderProduct(@PathVariable Long id, @PathVariable Long productId) {
Order order = getOrderById(id);
if (order != null) {
order.getProducts().removeIf(product -> product.getId().equals(productId));
}
return order;
}
@GetMapping("/{id}/product/{productId}")
public Product getProductById(@PathVariable Long id, @PathVariable Long productId) {
Order order = getOrderById(id);
if (order != null) {
List<Product> products = order.getProducts();
return products.stream().filter(product -> product.getId().equals(productId)).findFirst().orElse(null);
}
return null;
}
}
在实际开发中,Spring Boot 微服务架构设计与实现的应用场景非常广泛,如:
示例:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@SpringBootApplication
@EnableEurekaClient
public class ProductServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ProductServiceApplication.class, args);
}
}
@RestController
@RequestMapping("/api/products")
class ProductController {
private List<Product> products = new ArrayList<>();
public ProductController() {
products.add(new Product(1L, "P001", "手机", 1000.0, 100));
products.add(new Product(2L, "P002", "电脑", 5000.0, 50));
products.add(new Product(3L, "P003", "电视", 3000.0, 80));
products.add(new Product(4L, "P004", "手表", 500.0, 200));
products.add(new Product(5L, "P005", "耳机", 300.0, 150));
}
@GetMapping("/")
public List<Product> getAllProducts() {
return products;
}
@GetMapping("/{id}")
public Product getProductById(@PathVariable Long id) {
return products.stream().filter(product -> product.getId().equals(id)).findFirst().orElse(null);
}
@PostMapping("/")
public Product addProduct(@RequestBody Product product) {
product.setId((long) (products.size() + 1));
products.add(product);
return product;
}
@PutMapping("/{id}")
public Product updateProduct(@PathVariable Long id, @RequestBody Product product) {
Product existingProduct = getProductById(id);
if (existingProduct != null) {
existingProduct.setProductId(product.getProductId());
existingProduct.setProductName(product.getProductName());
existingProduct.setPrice(product.getPrice());
existingProduct.setSales(product.getSales());
}
return existingProduct;
}
@DeleteMapping("/{id}")
public void deleteProduct(@PathVariable Long id) {
products.removeIf(product -> product.getId().equals(id));
}
}
@SpringBootApplication
@EnableEurekaClient
public class OrderServiceApplication {
public static void main(String[] args) {
SpringApplication.run(OrderServiceApplication.class, args);
}
}
@RestController
@RequestMapping("/api/orders")
class OrderController {
@Autowired
private RestTemplate restTemplate;
private List<Order> orders = new ArrayList<>();
public OrderController() {
orders.add(new Order(1L, "O001", new ArrayList<>()));
orders.add(new Order(2L, "O002", new ArrayList<>()));
orders.add(new Order(3L, "O003", new ArrayList<>()));
}
@Bean
@LoadBalanced
public RestTemplate restTemplate() {
return new RestTemplate();
}
@GetMapping("/")
public List<Order> getAllOrders() {
return orders;
}
@GetMapping("/{id}")
public Order getOrderById(@PathVariable Long id) {
return orders.stream().filter(order -> order.getId().equals(id)).findFirst().orElse(null);
}
@PostMapping("/")
public Order addOrder(@RequestBody Order order) {
order.setId((long) (orders.size() + 1));
orders.add(order);
return order;
}
@PutMapping("/{id}")
public Order updateOrder(@PathVariable Long id, @RequestBody Order order) {
Order existingOrder = getOrderById(id);
if (existingOrder != null) {
existingOrder.setOrderId(order.getOrderId());
existingOrder.setProducts(order.getProducts());
}
return existingOrder;
}
@DeleteMapping("/{id}")
public void deleteOrder(@PathVariable Long id) {
orders.removeIf(order -> order.getId().equals(id));
}
@GetMapping("/{id}/products")
public List<Product> getOrderProducts(@PathVariable Long id) {
Order order = getOrderById(id);
if (order != null) {
List<Product> products = order.getProducts();
return products;
}
return new ArrayList<>();
}
@PostMapping("/{id}/products")
public Order addOrderProduct(@PathVariable Long id, @RequestBody Product product) {
Order order = getOrderById(id);
if (order != null) {
order.getProducts().add(product);
}
return order;
}
@DeleteMapping("/{id}/products/{productId}")
public Order deleteOrderProduct(@PathVariable Long id, @PathVariable Long productId) {
Order order = getOrderById(id);
if (order != null) {
order.getProducts().removeIf(product -> product.getId().equals(productId));
}
return order;
}
@GetMapping("/{id}/product/{productId}")
public Product getProductById(@PathVariable Long id, @PathVariable Long productId) {
Order order = getOrderById(id);
if (order != null) {
List<Product> products = order.getProducts();
return products.stream().filter(product -> product.getId().equals(productId)).findFirst().orElse(null);
}
return null;
}
}
// 测试类
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class OrderServiceApplicationTests {
@LocalServerPort
private int port;
@Autowired
private TestRestTemplate restTemplate;
@Test
void contextLoads() {}
@Test
void testGetAllOrders() {
List<Order> orders = restTemplate.getForObject("http://localhost:" + port + "/api/orders/", List.class);
assertThat(orders).isNotNull();
assertThat(orders.size()).isGreaterThanOrEqualTo(3);
}
@Test
void testAddOrder() {
Order order = new Order(null, "O004", new ArrayList<>());
Order savedOrder = restTemplate.postForObject("http://localhost:" + port + "/api/orders/", order, Order.class);
assertThat(savedOrder).isNotNull();
assertThat(savedOrder.getOrderId()).isEqualTo("O004");
}
@Test
void testAddOrderProduct() {
Product product = new Product(1L, "P001", "手机", 1000.0, 100);
HttpEntity<Product> requestEntity = new HttpEntity<>(product);
ResponseEntity<Order> response = restTemplate.exchange("http://localhost:" + port + "/api/orders/1/products", HttpMethod.POST, requestEntity, Order.class);
assertThat(response.getStatusCodeValue()).isEqualTo(200);
assertThat(response.getBody()).isNotNull();
assertThat(response.getBody().getProducts().size()).isGreaterThanOrEqualTo(1);
}
}
输出结果:
本章我们学习了 Spring Boot 微服务架构设计与实现,包括微服务架构的定义与特点、Spring Boot 与微服务的集成、Spring Boot 与微服务的配置、Spring Boot 与微服务的基本方法、Spring Boot 的实际应用场景,学会了在实际开发中处理微服务架构设计与实现问题。其中,微服务架构的定义与特点、Spring Boot 与微服务的集成、Spring Boot 与微服务的配置、Spring Boot 与微服务的基本方法、Spring Boot 的实际应用场景是本章的重点内容。

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online