完整微服务设计 功能实现

news2024/12/25 12:26:36

        我们将以一个简单的电商系统为例,实现微服务架构,逐步用Java代码详细实现每个模块,并配合注释帮助小白理解。在这个实现中,我们使用以下工具和框架:

  • Spring Boot:用于构建微服务。
  • Spring Cloud:用于服务注册、发现、负载均衡等。
  • Docker:用于容器化服务。
  • Kubernetes (K8s):用于部署到生产环境。
  • MySQL/MongoDB/PostgreSQL:不同服务独立数据库。
  • RabbitMQ:用于消息队列。
  • Prometheus + Grafana:用于监控。

以下是完整的实现步骤。


一、用户服务 (User Service)的实现

1. 环境搭建

1.1 必备工具安装

确保安装以下工具:

  • Java 17+
  • Maven
  • Docker
  • Kubernetes (minikube 或云上的K8s服务)
  • RabbitMQ
  • 数据库(MySQL/PostgreSQL/MongoDB)
  • IDE(IntelliJ IDEA 或 VS Code)

2. 功能

        管理用户信息(用户注册、查询)。

2.1 数据库准备

我们使用 PostgreSQL 来存储用户数据。

  • 创建数据库和表
CREATE DATABASE user_service;
CREATE TABLE users (
    id SERIAL PRIMARY KEY,
    username VARCHAR(255) NOT NULL UNIQUE,
    email VARCHAR(255) NOT NULL UNIQUE,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
2.2 创建 Spring Boot 项目

生成项目:Spring Initializr
依赖:

  • Spring Web
  • Spring Data JPA
  • PostgreSQL Driver

2.3 实现用户服务

application.yml 配置文件

配置数据库连接:

server:
  port: 8081  # 服务运行的端口号

spring:
  datasource:
    url: jdbc:postgresql://localhost:5432/user_service
    username: postgres  # 数据库用户名
    password: password  # 数据库密码
  jpa:
    hibernate:
      ddl-auto: update  # 自动更新数据库结构
    show-sql: true      # 显示 SQL 查询日志
User 实体类
package com.example.userservice.model;

import jakarta.persistence.*;
import java.time.LocalDateTime;

/**
 * 用户实体类,对应数据库表 users。
 */
@Entity
@Table(name = "users")
public class User {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;  // 用户唯一 ID

    @Column(nullable = false, unique = true)
    private String username;  // 用户名(唯一)

    @Column(nullable = false, unique = true)
    private String email;  // 用户邮箱(唯一)

    @Column(name = "created_at", updatable = false)
    private LocalDateTime createdAt = LocalDateTime.now();  // 用户注册时间

    // Getters 和 Setters,用于封装字段访问
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    public LocalDateTime getCreatedAt() {
        return createdAt;
    }

    public void setCreatedAt(LocalDateTime createdAt) {
        this.createdAt = createdAt;
    }
}
UserRepository 接口

package com.example.userservice.repository;

import com.example.userservice.model.User;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * 用户数据访问接口,提供 CRUD 操作。
 */
@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    User findByUsername(String username);  // 根据用户名查询用户
}
UserService 服务层
package com.example.userservice.service;

import com.example.userservice.model.User;
import com.example.userservice.repository.UserRepository;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * 用户服务类,包含业务逻辑。
 */
@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }

    /**
     * 注册新用户。
     * 
     * @param user 包含用户名和邮箱的用户对象
     * @return 保存后的用户对象,包含生成的 ID 和注册时间
     */
    public User registerUser(User user) {
        return userRepository.save(user);  // 保存到数据库
    }

    /**
     * 根据用户名查找用户。
     * 
     * @param username 要查询的用户名
     * @return 包含用户对象的 Optional,如果未找到则为空
     */
    public Optional<User> findUserByUsername(String username) {
        return Optional.ofNullable(userRepository.findByUsername(username));
    }
}
UserController 控制器
package com.example.userservice.controller;

import com.example.userservice.model.User;
import com.example.userservice.service.UserService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

import java.util.Optional;

/**
 * 用户服务的 REST 控制器。
 */
@RestController
@RequestMapping("/api/users")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    /**
     * 注册新用户的 API。
     * 
     * @param user 从请求体接收的用户对象
     * @return 返回注册成功的用户
     */
    @PostMapping
    public ResponseEntity<User> registerUser(@RequestBody User user) {
        return ResponseEntity.ok(userService.registerUser(user));
    }

    /**
     * 根据用户名查找用户的 API。
     * 
     * @param username 请求路径中的用户名
     * @return 返回找到的用户或 404
     */
    @GetMapping("/{username}")
    public ResponseEntity<User> findUserByUsername(@PathVariable String username) {
        Optional<User> user = userService.findUserByUsername(username);
        return user.map(ResponseEntity::ok).orElse(ResponseEntity.notFound().build());
    }
}

2.4 测试用户服务

启动服务后:

  1. 注册用户

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

    响应

    {
        "id": 1,
        "username": "haha_jam",
        "email": "haha@example.com",
        "createdAt": "2024-12-20T10:00:00"
    }
    
  2. 查询用户

    curl http://localhost:8081/api/users/haha_jam
    

    响应

    {
        "id": 1,
        "username": "haha_jam",
        "email": "haha@example.com",
        "createdAt": "2024-12-20T10:00:00"
    }
    

3. 服务注册与发现

        在完整微服务中,我们使用 Spring Cloud Eureka 来实现服务注册和发现。

3.1 什么是服务注册与发现?

        在微服务架构中,服务是分布式的,每个服务都可能运行在不同的主机或容器中。为了让服务之间能够互相通信,需要一种机制来找到其他服务的地址和端口。

服务注册与发现原理:
  1. Eureka Server:服务注册中心,用来维护所有服务的地址列表。每个服务(如用户服务、订单服务)都会向 Eureka Server 注册自己。
  2. Eureka Client:微服务实例本身会向 Eureka Server 注册,并定期发送心跳来告诉注册中心它是健康的。
  3. 服务发现:当一个服务需要调用另一个服务时,它会向 Eureka Server 查询目标服务的地址列表。

配置步骤包括:

  1. 创建 Eureka Server
  2. 将用户服务注册到 Eureka
  3. 添加 API 网关

3.2 创建 Eureka Server

Eureka Server 是服务注册中心,所有服务都会向它注册。

3.2.1 生成 Eureka Server 项目
  1. 打开 Spring Initializr。

  2. 配置项目:

    • Project: Maven
    • Language: Java
    • Spring Boot: 3.0.0+
    • Dependencies:
      • Spring Cloud Eureka Server
  3. 下载生成的项目并解压。


3.2.2 配置 Eureka Server
1. 添加依赖

在 pom.xml 中确认以下依赖已经存在:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
2. 配置 application.yml

在 src/main/resources/application.yml 中配置 Eureka Server:

server:
  port: 8761  # Eureka Server 的默认端口

spring:
  application:
    name: eureka-server  # 应用名称

eureka:
  client:
    register-with-eureka: false  # Eureka Server 本身不需要向其他注册中心注册
    fetch-registry: false        # Eureka Server 不需要获取注册信息
  server:
    enable-self-preservation: false  # 关闭自我保护模式(测试环境可以关闭,生产环境建议打开)
3. 启动类

在 src/main/java/com/example/eurekaserver/EurekaServerApplication.java 文件中添加 @EnableEurekaServer 注解。

package com.example.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;

/**
 * Eureka Server Application - 服务注册中心
 */
@SpringBootApplication
@EnableEurekaServer  // 启用 Eureka Server 功能
public class EurekaServerApplication {

    public static void main(String[] args) {
        SpringApplication.run(EurekaServerApplication.class, args);
    }
}

3.2.3 启动 Eureka Server
  1. 使用 IDE 或命令行运行 EurekaServerApplication
  2. 打开浏览器访问:http://localhost:8761
    • 你会看到 Eureka Server 的管理页面,显示 "No instances available"。

3.3 将用户服务注册到 Eureka

现在我们需要将前面实现的 用户服务(User Service) 注册到 Eureka Server。

3.3.1 添加依赖

在用户服务的 pom.xml 中添加 Eureka Client 依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
3.3.2 配置 application.yml

在 src/main/resources/application.yml 中添加 Eureka Client 配置:

server:
  port: 8081  # 用户服务运行的端口

spring:
  application:
    name: user-service  # 服务名称,Eureka 注册时的标识

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/  # Eureka Server 的地址
3.3.3 修改启动类

在用户服务的启动类中添加 @EnableEurekaClient 注解:

package com.example.userservice;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * User Service Application - 用户服务
 */
@SpringBootApplication
@EnableEurekaClient  // 启用 Eureka Client 功能
public class UserServiceApplication {

    public static void main(String[] args) {
        SpringApplication.run(UserServiceApplication.class, args);
    }
}

3.3.4 验证注册
  1. 启动 Eureka Server
  2. 启动 用户服务
  3. 在浏览器访问:http://localhost:8761
    • 你会看到 user-service 出现在 "Instances currently registered with Eureka" 列表中。

3.4 添加 API 网关

API 网关用于转发客户端请求到具体的微服务,并支持负载均衡。

3.4.1 创建 API 网关项目
  1. 打开 Spring Initializr。
  2. 配置项目:
    • Project: Maven
    • Language: Java
    • Spring Boot: 3.0.0+
    • Dependencies:
      • Spring Cloud Gateway
      • Spring Cloud Eureka Discovery

3.4.2 配置 API 网关
1. 添加依赖

在 pom.xml 中确认以下依赖:

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
2. 配置 application.yml

在 src/main/resources/application.yml 中配置网关:

server:
  port: 8080  # API 网关运行的端口

spring:
  application:
    name: api-gateway  # 应用名称
  cloud:
    gateway:
      routes:
        - id: user-service  # 路由 ID
          uri: lb://user-service  # 用户服务(通过 Eureka 注册的服务名)
          predicates:
            - Path=/api/users/**  # 匹配以 /api/users 开头的请求

eureka:
  client:
    service-url:
      defaultZone: http://localhost:8761/eureka/  # Eureka Server 地址
3. 启动类

在 src/main/java/com/example/apigateway/ApiGatewayApplication.java 文件中添加 @EnableEurekaClient 注解。

package com.example.apigateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

/**
 * API Gateway Application - 网关服务
 */
@SpringBootApplication
@EnableEurekaClient  // 启用 Eureka Client 功能
public class ApiGatewayApplication {

    public static void main(String[] args) {
        SpringApplication.run(ApiGatewayApplication.class, args);
    }
}

3.4.3 验证 API 网关
  1. 启动 Eureka Server
  2. 启动 用户服务
  3. 启动 API 网关
  4. 测试 API:
    curl http://localhost:8080/api/users/john_doe
    
    • API 网关会将请求转发到用户服务,返回用户数据。

4. 部署到K8S

4.1 容器化服务 (Docker)

在项目根目录下创建 Dockerfile

FROM openjdk:17-jdk-slim
COPY target/user-service-0.0.1-SNAPSHOT.jar user-service.jar
ENTRYPOINT ["java", "-jar", "/user-service.jar"]

4.2 构建Docker镜像

  1. 打包项目

    mvn clean package -DskipTests
    
  2. 构建镜像

    docker build -t user-service:1.0 .
    
  3. 运行容器

    docker run -d -p 8081:8081 user-service:1.0

4.3 部署到 Kubernetes

创建 user-service-deployment.yml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: user-service
spec:
  replicas: 3
  selector:
    matchLabels:
      app: user-service
  template:
    metadata:
      labels:
        app: user-service
    spec:
      containers:
        - name: user-service
          image: user-service:1.0
          ports:
            - containerPort: 8081
---
apiVersion: v1
kind: Service
metadata:
  name: user-service
spec:
  selector:
    app: user-service
  ports:
    - protocol: TCP
      port: 80
      targetPort: 8081
  type: LoadBalancer


4.4 部署到 K8s 集群

  1. 应用配置

    kubectl apply -f user-service-deployment.yml
    
  2. 查看服务

    kubectl get services

二、产品服务 (Product Service) 和订单服务 (Order Service)的实现

        每个服务有自己的数据库,提供REST API,并实现服务注册和发现,确保服务之间的解耦和可扩展性。

1. 产品服务 (Product Service)

功能:管理商品信息,包括商品的添加、修改和查询。

1.1 数据库准备

我们使用 MongoDB 来存储商品数据。

  • 创建数据库和集合
use product_service;
db.createCollection("products");
1.2 创建 Spring Boot 项目

生成项目:Spring Initializr
依赖:

  • Spring Web
  • Spring Data MongoDB
1.3 实现产品服务
application.yml 配置文件

配置MongoDB连接:

server:
  port: 8082

spring:
  data:
    mongodb:
      uri: mongodb://localhost:27017/product_service
Product 实体类
package com.example.productservice.model;

import org.springframework.data.annotation.Id;
import org.springframework.data.mongodb.core.mapping.Document;

/**
 * 在MongoDB中表示产品文档的产品实体类。
 */
@Document(collection = "products")
public class Product {

    @Id
    private String id;  // 商品ID,由MongoDB生成

    private String name;  // 商品名称
    private String description;  // 商品描述
    private double price;  // 商品价格
    private int stock;  // 商品库存

    // Getters and Setters
    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public int getStock() {
        return stock;
    }

    public void setStock(int stock) {
        this.stock = stock;
    }
}

ProductRepository 接口

package com.example.productservice.repository;

import com.example.productservice.model.Product;
import org.springframework.data.mongodb.repository.MongoRepository;
import org.springframework.stereotype.Repository;

/**
 * 用于在Product实体上执行CRUD操作的存储库接口。
 */
@Repository
public interface ProductRepository extends MongoRepository<Product, String> {
    Product findByName(String name);  // 根据商品名称查询商品
}
ProductService 服务层
package com.example.productservice.service;

import com.example.productservice.model.Product;
import com.example.productservice.repository.ProductRepository;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * 管理产品的服务类。包含产品相关操作的业务逻辑。
 */
@Service
public class ProductService {

    private final ProductRepository productRepository;

    public ProductService(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    /**
     * 添加新产品。
     * 
     * @param product 包含产品详细信息的产品对象。
     * @return Saved 带生成ID的产品对象
     */
    public Product addProduct(Product product) {
        return productRepository.save(product);
    }

    /**
     * 按名称查找产品。
     * 
     * @param name 产品名称。
     * @return 含有找到的产品,如果没有找到则为空。
     */
    public Optional<Product> findProductByName(String name) {
        return Optional.ofNullable(productRepository.findByName(name));
    }

    /**
     * 按指定数量减少库存。
     * 
     * @param productId 产品ID。
     * @param quantity 数量减少。
     * @return 更新了Product对象。
     */
    public Product decreaseStock(String productId, int quantity) {
        Product product = productRepository.findById(productId).orElseThrow(() -> new RuntimeException("Product not found"));
        if (product.getStock() >= quantity) {
            product.setStock(product.getStock() - quantity);
            return productRepository.save(product);
        } else {
            throw new RuntimeException("Insufficient stock");
        }
    }
}

ProductController 控制器

package com.example.productservice.controller;

import com.example.productservice.model.Product;
import com.example.productservice.service.ProductService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * 与产品相关的端点的REST控制器。
 */
@RestController
@RequestMapping("/api/products")
public class ProductController {

    private final ProductService productService;

    public ProductController(ProductService productService) {
        this.productService = productService;
    }

    /**
     * 添加新产品的端点。
     * 
     * @param product 请求体中的产品对象。
     * @return 包含已保存产品的responseentity。
     */
    @PostMapping
    public ResponseEntity<Product> addProduct(@RequestBody Product product) {
        return ResponseEntity.ok(productService.addProduct(product));
    }

    /**
     * 根据名称查找产品的端点。
     * 
     * @param name 产品名称作为路径变量传递。
     * @return 包含产品,如果找到。
     */
    @GetMapping("/{name}")
    public ResponseEntity<Product> findProductByName(@PathVariable String name) {
        return productService.findProductByName(name)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }

    /**
     * 减少产品库存的终点。
     * 
     * @param productId 产品ID。
     * @param quantity 数量减少。
     * @return 包含更新后的产品。
     */
    @PutMapping("/{productId}/decrease-stock/{quantity}")
    public ResponseEntity<Product> decreaseStock(@PathVariable String productId, @PathVariable int quantity) {
        return ResponseEntity.ok(productService.decreaseStock(productId, quantity));
    }
}
1.4 测试产品服务

启动服务后:

  1. 添加商品

    curl -X POST -H "Content-Type: application/json" \
    -d '{"name": "Laptop", "description": "High-performance laptop", "price": 1000, "stock": 50}' \
    http://localhost:8082/api/products
    

    响应

    {
        "id": "605c72ef1532072a20b0f119",
        "name": "Laptop",
        "description": "High-performance laptop",
        "price": 1000,
        "stock": 50
    }
    
  2. 查询商品

    curl http://localhost:8082/api/products/Laptop
    

    响应

    {
        "id": "605c72ef1532072a20b0f119",
        "name": "Laptop",
        "description": "High-performance laptop",
        "price": 1000,
        "stock": 50
    }
    

2. 订单服务 (Order Service)

功能:管理用户的订单,包括创建订单、查询订单、更新订单状态等。

2.1 数据库准备

我们使用 MySQL 来存储订单数据。

  • 创建数据库和表
CREATE DATABASE order_service;
CREATE TABLE orders (
    id INT AUTO_INCREMENT PRIMARY KEY,
    user_id INT NOT NULL,
    product_id VARCHAR(255) NOT NULL,
    quantity INT NOT NULL,
    total_price DOUBLE NOT NULL,
    order_status VARCHAR(255) DEFAULT 'PENDING',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
2.2 创建 Spring Boot 项目

生成项目:Spring Initializr
依赖:

  • Spring Web
  • Spring Data JPA
  • MySQL Driver
2.3 实现订单服务
application.yml 配置文件

配置MySQL连接:

server:
  port: 8083

spring:
  datasource:
    url: jdbc:mysql://localhost:3306/order_service
    username: root
    password: root
  jpa:
    hibernate:
      ddl-auto: update
    show-sql: true
Order 实体类
package com.example.orderservice.model;

import jakarta.persistence.*;
import java.time.LocalDateTime;

/**
 * 表示数据库中的订单表的订单实体类。
 */
@Entity
@Table(name = "orders")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    @Column(nullable = false)
    private Long userId;  // 用户ID

    @Column(nullable = false)
    private String productId;  // 商品ID

    @Column(nullable = false)
    private int quantity;  // 购买数量

    @Column(nullable = false)
    private double totalPrice;  // 总金额

    @Column(name = "order_status", nullable = false)
    private String orderStatus = "PENDING";  // 订单状态

    @Column(name = "created_at", updatable = false
)
    private LocalDateTime createdAt = LocalDateTime.now();  // 订单创建时间

    // Getters and Setters
}

OrderRepository 接口

package com.example.orderservice.repository;

import com.example.orderservice.model.Order;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;

/**
 * 用于在Order实体上执行CRUD操作的存储库接口。
 */
@Repository
public interface OrderRepository extends JpaRepository<Order, Long> {
    Order findByUserIdAndOrderStatus(Long userId, String orderStatus);  // 根据用户ID和订单状态查询订单
}
OrderService 服务层
package com.example.orderservice.service;

import com.example.orderservice.model.Order;
import com.example.orderservice.repository.OrderRepository;
import org.springframework.stereotype.Service;

import java.util.Optional;

/**
 * 用于管理订单的服务类。包含订单相关操作的业务逻辑。
 */
@Service
public class OrderService {

    private final OrderRepository orderRepository;

    public OrderService(OrderRepository orderRepository) {
        this.orderRepository = orderRepository;
    }

    /**
     * 创建一个新订单。
     * 
     * @param order 包含订单详细信息的订单对象。
     * @return 保存订单对象。
     */
    public Order createOrder(Order order) {
        return orderRepository.save(order);
    }

    /**
     * 通过用户ID和状态查找订单。
     * 
     * @param userId 用户ID。
     * @param orderStatus 订单状态(例如,‘PENDING’)。
     * @return 可选,包含找到的订单,如果没有找到则为空。
     */
    public Optional<Order> findOrderByUserIdAndStatus(Long userId, String orderStatus) {
        return Optional.ofNullable(orderRepository.findByUserIdAndOrderStatus(userId, orderStatus));
    }
}
OrderController 控制器
package com.example.orderservice.controller;

import com.example.orderservice.model.Order;
import com.example.orderservice.service.OrderService;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;

/**
 * 与订单相关的端点的REST控制器。
 */
@RestController
@RequestMapping("/api/orders")
public class OrderController {

    private final OrderService orderService;

    public OrderController(OrderService orderService) {
        this.orderService = orderService;
    }

    /**
     * 创建新订单的端点。
     * 
     * @param order 从请求体中订购对象。
     * @return ResponseEntity包含保存的订单。
     */
    @PostMapping
    public ResponseEntity<Order> createOrder(@RequestBody Order order) {
        return ResponseEntity.ok(orderService.createOrder(order));
    }

    /**
     * 根据用户ID和状态查找订单的端点。
     * 
     * @param userId 用户ID。
     * @param orderStatus 订单状态作为路径变量传递。
     * @return ResponseEntity包含找到的订单,如果存在。
     */
    @GetMapping("/{userId}/{orderStatus}")
    public ResponseEntity<Order> findOrderByUserIdAndStatus(@PathVariable Long userId, @PathVariable String orderStatus) {
        return orderService.findOrderByUserIdAndStatus(userId, orderStatus)
                .map(ResponseEntity::ok)
                .orElse(ResponseEntity.notFound().build());
    }
}

总结

        在这个扩展中,我们设计了三个服务:用户服务,产品服务订单服务。每个服务具有自己的数据库,提供REST API,能够完成各自的功能,如商品管理、订单创建与查询。服务之间通过HTTP协议相互通信,服务之间通过微服务架构进行解耦,确保系统可扩展和维护。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2265282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Yonghong 企业日常问题 06】上传的文件不在白名单,修改allow.jar.digest属性添加允许上传的文件SH256值?

文章目录 前言问题描述问题分析问题解决1.允许所有用户上传驱动文件2.如果是想只上传白名单的驱动 前言 该方法适合永洪BI系列产品&#xff0c;包括不限于vividime desktop&#xff0c;vividime z-suit&#xff0c;vividime x-suit产品。 问题描述 当我们连接数据源的时候&a…

我的JAVA-Web基础(2)

1.JDBC 防止sql注入 2.JSP JSP的基本语法 基本语法是 <% %> Java代码 <% %> 输出变量 可以转换成${变量}的EL表达式 <%! %>定义变量 JSP的基本语法包括以下几个主要部分&#xff1a; 1. 表达式&#xff08;Expression&#xff09; 表达式用于将…

新闻网站的个性化推荐:机器学习的应用

3.1可行性分析 开发者在进行开发系统之前&#xff0c;都需要进行可行性分析&#xff0c;保证该系统能够被成功开发出来。 3.1.1技术可行性 开发该新闻网站所采用的技术是vue和MYSQL数据库。计算机专业的学生在学校期间已经比较系统的学习了很多编程方面的知识&#xff0c;同时也…

IIC驱动EEPROM

代码参考正点原子 i2c_dri:主要是三段式状态机的编写 module iic_dri#(parameter SLAVE_ADDR 7b1010000 , //EEPROM从机地址parameter CLK_FREQ 26d50_000_000, //模块输入的时钟频率parameter I2C_FREQ 18d250_000 //IIC_SCL的时钟频率)( …

【动手学轨迹预测】2.3 场景表征方法

场景表征是指在所有可用的场景信息数据中, 提取出对于预测网络有用的数据, 并将其转换为易于模型学习的数据格式. 对于预测网络来说, 最重要的数据是交通参与者的历史轨迹和地图信息, 表达它们的常见方法有:栅格化和稀疏化 2.1.1 栅格化 多通道表达 如上图所示, 将历史轨迹和…

亚信安全举办“判大势 悟思想 强实践”主题党日活动

为深入学习和贯彻党的二十届三中全会精神&#xff0c;近日&#xff0c;亚信安全举办了 “学习贯彻党的二十届三中全会精神——‘判大势 悟思想 强实践’党日活动”&#xff0c;并取得圆满成功。 本次活动特邀南京市委宣讲团成员、南京市委党校市情研究中心主任王辉龙教授出席。…

医疗大模型威胁攻击下的医院AI安全:挑战与应对策略

一、引言 1.1 研究背景与意义 随着人工智能技术的迅猛发展,医疗大模型作为一种新兴的技术手段,正逐渐渗透到医疗领域的各个环节,为医疗服务的数字化转型带来了前所未有的机遇。从辅助诊断到疾病预测,从个性化治疗方案的制定到医疗资源的优化配置,医疗大模型展现出了巨大…

如何在谷歌浏览器中使用内置翻译功能

谷歌浏览器作为全球最受欢迎的网络浏览器之一&#xff0c;提供了强大且便捷的内置翻译功能。这一功能帮助用户轻松跨越语言障碍&#xff0c;浏览不同语言的网页内容。本文将详细介绍如何在谷歌浏览器中使用其内置翻译功能。 一、启用谷歌浏览器内置翻译功能 1、打开谷歌浏览器…

【MySQL】7.0 入门学习(七)——MySQL基本指令:帮助、清除输入、查询等

1.0 help &#xff1f; 帮助指令&#xff0c;查询某个指令的解释、用法、说明等。详情参考博文&#xff1a; 【数据库】6.0 MySQL入门学习&#xff08;六&#xff09;——MySQL启动与停止、官方手册、文档查询 https://www.cnblogs.com/xiaofu007/p/10301005.html 2.0 在cmd命…

基于推理的目标检测 DetGPT

基于推理的目标检测 DetGPT flyfish detgpt.github.io 近年来&#xff0c;由于大型语言模型&#xff08;LLMs&#xff09;的发展&#xff0c;计算机视觉领域取得了重大进展。这些模型使人类与机器之间能够进行更有效、更复杂的交互&#xff0c;为模糊人类与机器智能界限的新技…

概率论 期末 笔记

第一章 随机事件及其概率 利用“四大公式”求事件概率 全概率公式与贝叶斯公式 伯努利概型求概率 习题 推导 一维随机变量及其分布 离散型随机变量&#xff08;R.V&#xff09;求分布律 利用常见离散型分布求概率 连续型R.V相关计算 利用常见连续型分布的计算 均匀分布 正态…

探索 Python编程 调试案例:计算小程序中修复偶数的bug

在 学习Python 编程的过程里&#xff0c;会遇到各种各样的bug。而修复bug调试代码就像是一场充满挑战的侦探游戏。每一个隐藏的 bug 都是谜题&#xff0c;等待开发者去揭开真相&#xff0c;让程序可以顺利运行。今天&#xff0c;让我们通过一个实际案例&#xff0c;深入探索 Py…

Redis 介绍和安装

个人主页&#xff1a;C忠实粉丝 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 C忠实粉丝 原创 Redis 入门介绍 收录于专栏[redis] 本专栏旨在分享学习Linux的一点学习笔记&#xff0c;欢迎大家在评论区交流讨论&#x1f48c; 本章将带领读者进入 Redis 的世…

springboot480基于springboot高校就业招聘系统设计和实现(论文+源码)_kaic

摘 要 信息数据从传统到当代&#xff0c;是一直在变革当中&#xff0c;突如其来的互联网让传统的信息管理看到了革命性的曙光&#xff0c;因为传统信息管理从时效性&#xff0c;还是安全性&#xff0c;还是可操作性等各个方面来讲&#xff0c;遇到了互联网时代才发现能补上自古…

【基础篇】1. JasperSoft Studio编辑器与报表属性介绍

编辑器介绍 Jaspersoft Studio有一个多选项卡编辑器&#xff0c;其中包括三个标签&#xff1a;设计&#xff0c;源代码和预览。 Design&#xff1a;报表设计页面&#xff0c;可以图形化拖拉组件设计报表&#xff0c;打开报表文件的主页面Source&#xff1a;源代码页码&#xff…

【河南新标】豫财预〔2024〕105号-《关于省级政务信息化建设项目支出预算标准的规定》-费用标准解读系列29

2024年12月3日&#xff0c;河南省财政厅发布了《关于省级政务信息化建设项目支出预算标准的规定》豫财预〔2024〕105号。《关于省级政务信息化建设项目支出预算标准的规定 &#xff08;试行&#xff09;》&#xff08;豫财预 〔2020〕81号&#xff09;同时废止。新的豫财预〔20…

导入numpy报错:PyCapsule_Import could not import module “datetime“

背景 docker部署深度学习算法时&#xff0c;安装miniconda报错&#xff0c;报线程错误。 然后在构建镜像时把miniconda装进去没有问题。 然后把环境移进去发现报numpy导入错误 在python解释器尝试导入numpy发现还是报错 尝试重新装numpy&#xff0c;发现没有解决。 网上找解决方…

TANGO与LabVIEW控制系统集成

TANGO 是一个开源的设备控制和数据采集框架&#xff0c;主要用于管理实验室设备、自动化系统和工业设备。它为不同类型的硬件提供统一的控制接口&#xff0c;并支持设备之间的通信&#xff0c;广泛应用于粒子加速器、同步辐射光源、实验室自动化和工业控制等领域。 1. TANGO的核…

利用Circuit JS1再学学电子方面的知识(硬件)

1 电阻器 1.1 电阻并联 每个电阻电压相同&#xff0c;总电流等于各支路电流之和。 并联电阻值 R 1/(1/R11/R2);R约等于90.9 电阻并联后的阻值比最小的一个电阻值都小。 1.2 电阻串联 电阻串联的阻值为各电阻阻值相加。 RR1R2&#xff0c;串联涉及电阻分压。 一般在开关处…

使用Amazon Bedrock的无服务器的智能工作流

使用Amazon Bedrock的无服务器的智能工作流 智能工作流基于用户输入处理不可预见的任务&#xff0c;比如发起API调用。无服务器架构可以高效地管理这些任务和不同的工作负载&#xff0c;而无需维护服务器&#xff0c;从而加快部署速度。 你将学习如何通过使用带有保护措施的智能…