Spring Boot 微服務架構設計與實現代碼
Spring Boot 微服務架構設計與實現
25.1 學習目標與重點提示
學習目標:掌握Spring Boot微服務架構設計與實現的核心概念與使用方法,包括微服務架構的定義與特點、Spring Boot與微服務的集成、Spring Boot與微服務的配置、Spring Boot與微服務的基本方法、Spring Boot的實際應用場景,學會在實際開發(fā)中處理微服務架構設計與實現問題。
重點:微服務架構的定義與特點、Spring Boot與微服務的集成、Spring Boot與微服務的配置、Spring Boot與微服務的基本方法、Spring Boot的實際應用場景。
25.2 微服務架構概述
微服務架構是Java開發(fā)中的重要組件。
25.2.1 微服務架構的定義
定義:微服務架構是一種軟件架構風格,將應用程序拆分為一組獨立的服務,每個服務運行在自己的進程中,通過網絡進行通信。
作用:
- 提高應用程序的可擴展性。
- 提高應用程序的可維護性。
- 提高應用程序的可靠性。
常見的微服務架構:
- Spring Cloud:Spring Cloud是Spring Boot提供的微服務框架。
- Netflix OSS:Netflix OSS是Netflix提供的微服務框架。
- Docker:Docker是一種容器化技術,用于打包和部署應用程序。
- Kubernetes:Kubernetes是一種容器編排工具,用于管理和調度應用程序。
? 結論:微服務架構是一種軟件架構風格,作用是提高應用程序的可擴展性、可維護性、可靠性。
25.2.2 微服務架構的特點
定義:微服務架構的特點是指微服務架構的特性。
特點:
- 獨立部署:每個服務可以獨立部署。
- 獨立開發(fā):每個服務可以獨立開發(fā)。
- 獨立運行:每個服務運行在自己的進程中。
- 網絡通信:每個服務通過網絡進行通信。
? 結論:微服務架構的特點包括獨立部署、獨立開發(fā)、獨立運行、網絡通信。
25.3 Spring Boot與微服務的集成
Spring Boot與微服務的集成是Java開發(fā)中的重要內容。
25.3.1 集成Spring Cloud Eureka的步驟
定義:集成Spring Cloud Eureka的步驟是指使用Spring Boot與Spring Cloud Eureka集成的方法。
步驟:
- 創(chuàng)建Spring Boot項目。
- 添加所需的依賴。
- 配置Spring Cloud Eureka。
- 創(chuàng)建服務提供者。
- 創(chuàng)建服務消費者。
- 測試應用。
示例:
服務注冊中心(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);
}
}? 結論:集成Spring Cloud Eureka的步驟包括創(chuàng)建Spring Boot項目、添加所需的依賴、配置Spring Cloud Eureka、創(chuàng)建服務提供者、創(chuàng)建服務消費者、測試應用。
25.4 Spring Boot與微服務的配置
Spring Boot與微服務的配置是Java開發(fā)中的重要內容。
25.4.1 配置Spring Cloud Config
定義:配置Spring Cloud Config是指使用Spring Boot與Spring Cloud Config集成的方法。
步驟:
- 創(chuàng)建Spring Boot項目。
- 添加所需的依賴。
- 配置Spring Cloud Config。
- 創(chuàng)建配置文件。
- 測試應用。
示例:
配置服務器(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
? 結論:配置Spring Cloud Config是指使用Spring Boot與Spring Cloud Config集成的方法,步驟包括創(chuàng)建Spring Boot項目、添加所需的依賴、配置Spring Cloud Config、創(chuàng)建配置文件、測試應用。
25.5 Spring Boot與微服務的基本方法
Spring Boot與微服務的基本方法包括使用Ribbon、使用Feign、使用Hystrix。
25.5.1 使用Ribbon
定義:使用Ribbon是指Spring Boot與微服務集成的基本方法之一。
作用:
- 實現服務間的通信。
- 提高應用程序的性能。
示例:
服務消費者(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;
}
}? 結論:使用Ribbon是指Spring Boot與微服務集成的基本方法之一,作用是實現服務間的通信、提高應用程序的性能。
25.6 Spring Boot的實際應用場景
在實際開發(fā)中,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);
}
}輸出結果:
- 訪問http://localhost:8082/api/orders/:返回所有訂單信息。
- 訪問http://localhost:8082/api/orders/1/products:返回訂單1的產品信息。
? 結論:在實際開發(fā)中,Spring Boot微服務架構設計與實現的應用場景非常廣泛,需要根據實際問題選擇合適的微服務架構和工具。
總結
本章我們學習了Spring Boot微服務架構設計與實現,包括微服務架構的定義與特點、Spring Boot與微服務的集成、Spring Boot與微服務的配置、Spring Boot與微服務的基本方法、Spring Boot的實際應用場景,學會了在實際開發(fā)中處理微服務架構設計與實現問題。其中,微服務架構的定義與特點、Spring Boot與微服務的集成、Spring Boot與微服務的配置、Spring Boot與微服務的基本方法、Spring Boot的實際應用場景是本章的重點內容。從下一章開始,我們將學習Spring Boot的其他組件、微服務等內容。
到此這篇關于Spring Boot 微服務架構設計與實現的文章就介紹到這了,更多相關Spring Boot 微服務架構內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
Java入門基礎之常規(guī)的命名方法和變量的值及其引用
這篇文章主要介紹了Java的命名方法和變量的值及其引用,是Java入門學習中的基礎知識,需要的朋友可以參考下2015-09-09
springboot2.0.0配置多數據源出現jdbcUrl is required with driverClassN
這篇文章主要介紹了springboot2.0.0配置多數據源出現jdbcUrl is required with driverClassName的錯誤,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-11-11
Spring中任務調度之解讀@Scheduled和@Schedules注解的使用
這篇文章主要介紹了Spring中任務調度之解讀@Scheduled和@Schedules注解的使用,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04
Spring Cloud 的 Hystrix.功能及實踐詳解
這篇文章主要介紹了Spring Cloud 的 Hystrix.功能及實踐詳解,Hystrix 具備服務降級、服務熔斷、線程和信號隔離、請求緩存、請求合并以及服務監(jiān)控等強大功能,需要的朋友可以參考下2019-07-07

