学习时间: 4-5小时
学习目标: 掌握Spring Cloud Gateway的使用,学会构建API网关和路由管理
详细学习清单
✅ 第一部分:API网关基础概念(60分钟)
1. 网关的作用与特点
网关核心功能
diff
- 路由转发:将请求路由到不同的微服务
- 负载均衡:在多个服务实例间分发请求
- 安全认证:统一的安全控制和权限验证
- 限流熔断:保护后端服务不被过载
- 日志监控:统一的请求日志和监控
- 协议转换:支持不同协议间的转换
网关架构图
java
// GatewayArchitecture.java
package com.example.demo.gateway;
public class GatewayArchitecture {
public static void main(String[] args) {
System.out.println("=== API网关架构组件 ===");
System.out.println("1. 客户端请求 → API网关");
System.out.println("2. 网关路由 → 微服务");
System.out.println("3. 网关过滤 → 请求/响应处理");
System.out.println("4. 网关聚合 → 多个服务响应");
System.out.println("5. 网关监控 → 性能指标收集");
}
}
2. 网关设计模式
网关设计模式
java
// GatewayPatterns.java
package com.example.demo.gateway;
import java.util.List;
import java.util.ArrayList;
public class GatewayPatterns {
public static class GatewayPattern {
private String name;
private String description;
private List<String> useCases;
private List<String> advantages;
public GatewayPattern(String name, String description) {
this.name = name;
this.description = description;
this.useCases = new ArrayList<>();
this.advantages = new ArrayList<>();
}
public void addUseCase(String useCase) {
this.useCases.add(useCase);
}
public void addAdvantage(String advantage) {
this.advantages.add(advantage);
}
// Getter方法
public String getName() { return name; }
public String getDescription() { return description; }
public List<String> getUseCases() { return useCases; }
public List<String> getAdvantages() { return advantages; }
}
public static void main(String[] args) {
// 路由模式
GatewayPattern routingPattern = new GatewayPattern("路由模式", "根据请求路径将请求路由到不同服务");
routingPattern.addUseCase("微服务路由");
routingPattern.addUseCase("版本控制");
routingPattern.addUseCase("A/B测试");
routingPattern.addAdvantage("灵活的路由配置");
routingPattern.addAdvantage("支持动态路由");
// 聚合模式
GatewayPattern aggregationPattern = new GatewayPattern("聚合模式", "将多个微服务的响应聚合为一个响应");
aggregationPattern.addUseCase("用户信息聚合");
aggregationPattern.addUseCase("订单详情聚合");
aggregationPattern.addUseCase("仪表板数据聚合");
aggregationPattern.addAdvantage("减少客户端请求");
aggregationPattern.addAdvantage("提升用户体验");
// 过滤模式
GatewayPattern filterPattern = new GatewayPattern("过滤模式", "在请求处理过程中添加通用逻辑");
filterPattern.addUseCase("认证授权");
filterPattern.addUseCase("日志记录");
filterPattern.addUseCase("限流熔断");
filterPattern.addAdvantage("代码复用");
filterPattern.addAdvantage("统一处理");
System.out.println("=== 网关设计模式 ===");
printGatewayPattern(routingPattern);
printGatewayPattern(aggregationPattern);
printGatewayPattern(filterPattern);
}
private static void printGatewayPattern(GatewayPattern pattern) {
System.out.println("\n模式名称: " + pattern.getName());
System.out.println("模式描述: " + pattern.getDescription());
System.out.println("使用场景:");
for (String useCase : pattern.getUseCases()) {
System.out.println(" - " + useCase);
}
System.out.println("优势特点:");
for (String advantage : pattern.getAdvantages()) {
System.out.println(" - " + advantage);
}
}
}
✅ 第二部分:Spring Cloud Gateway配置(90分钟)
1. 网关服务配置
网关服务pom.xml
xml
<!-- gateway-service/pom.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>
<parent>
<groupId>com.example</groupId>
<artifactId>microservice-parent</artifactId>
<version>1.0.0</version>
</parent>
<artifactId>gateway-service</artifactId>
<dependencies>
<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>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
</dependencies>
</project>
网关服务主类
java
// GatewayApplication.java
package com.example.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
@SpringBootApplication
@EnableDiscoveryClient
public class GatewayApplication {
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
网关服务配置
yaml
# gateway-service/src/main/resources/application.yml
server:
port: 8080
spring:
application:
name: gateway-service
cloud:
gateway:
discovery:
locator:
enabled: true
lower-case-service-id: true
routes:
# 用户服务路由
- id: user-service-route
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 10
redis-rate-limiter.burstCapacity: 20
- name: Retry
args:
retries: 3
statuses: BAD_GATEWAY
# 订单服务路由
- id: order-service-route
uri: lb://order-service
predicates:
- Path=/api/orders/**
filters:
- StripPrefix=1
- name: RequestRateLimiter
args:
redis-rate-limiter.replenishRate: 5
redis-rate-limiter.burstCapacity: 10
# 商品服务路由
- id: product-service-route
uri: lb://product-service
predicates:
- Path=/api/products/**
filters:
- StripPrefix=1
# 支付服务路由
- id: payment-service-route
uri: lb://payment-service
predicates:
- Path=/api/payments/**
filters:
- StripPrefix=1
# 文件服务路由
- id: file-service-route
uri: lb://file-service
predicates:
- Path=/api/files/**
filters:
- StripPrefix=1
# 通知服务路由
- id: notification-service-route
uri: lb://notification-service
predicates:
- Path=/api/notifications/**
filters:
- StripPrefix=1
eureka:
client:
service-url:
defaultZone: http://localhost:8761/eureka/
instance:
prefer-ip-address: true
management:
endpoints:
web:
exposure:
include: health,info,gateway
endpoint:
health:
show-details: always
# Redis配置
spring:
redis:
host: localhost
port: 6379
database: 0
timeout: 2000ms
lettuce:
pool:
max-active: 8
max-wait: -1ms
max-idle: 8
min-idle: 0
2. 自定义过滤器
全局认证过滤器
java
// GlobalAuthFilter.java
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Arrays;
import java.util.List;
@Component
public class GlobalAuthFilter implements GlobalFilter, Ordered {
// 不需要认证的路径
private static final List<String> WHITE_LIST = Arrays.asList(
"/api/auth/login",
"/api/auth/register",
"/api/auth/refresh",
"/api/public/**",
"/actuator/**"
);
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().value();
// 检查是否是白名单路径
if (isWhiteListPath(path)) {
return chain.filter(exchange);
}
// 获取Authorization头
String token = getTokenFromRequest(request);
if (!StringUtils.hasText(token)) {
return unauthorized(exchange, "缺少认证令牌");
}
// 验证token(这里简化处理,实际应该调用认证服务)
if (!isValidToken(token)) {
return unauthorized(exchange, "无效的认证令牌");
}
// 添加用户信息到请求头
ServerHttpRequest modifiedRequest = request.mutate()
.header("X-User-Id", getUserIdFromToken(token))
.header("X-User-Roles", getUserRolesFromToken(token))
.build();
return chain.filter(exchange.mutate().request(modifiedRequest).build());
}
@Override
public int getOrder() {
return -100; // 高优先级
}
private boolean isWhiteListPath(String path) {
return WHITE_LIST.stream().anyMatch(path::startsWith);
}
private String getTokenFromRequest(ServerHttpRequest request) {
String bearerToken = request.getHeaders().getFirst(HttpHeaders.AUTHORIZATION);
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {
return bearerToken.substring(7);
}
return null;
}
private boolean isValidToken(String token) {
// 这里应该调用认证服务验证token
// 简化实现,实际项目中需要集成JWT验证
return StringUtils.hasText(token) && token.length() > 10;
}
private String getUserIdFromToken(String token) {
// 从token中解析用户ID
// 简化实现,实际应该解析JWT
return "user123";
}
private String getUserRolesFromToken(String token) {
// 从token中解析用户角色
// 简化实现,实际应该解析JWT
return "USER,ADMIN";
}
private Mono<Void> unauthorized(ServerWebExchange exchange, String message) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
}
请求日志过滤器
java
// RequestLogFilter.java
package com.example.gateway.filter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class RequestLogFilter implements GlobalFilter, Ordered {
private static final Logger logger = LoggerFactory.getLogger(RequestLogFilter.class);
private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().value();
String method = request.getMethod().name();
String remoteAddress = request.getRemoteAddress() != null ?
request.getRemoteAddress().getAddress().getHostAddress() : "unknown";
long startTime = System.currentTimeMillis();
logger.info("=== 请求开始 ===");
logger.info("时间: {}", LocalDateTime.now().format(formatter));
logger.info("路径: {} {}", method, path);
logger.info("来源IP: {}", remoteAddress);
logger.info("请求头: {}", request.getHeaders());
return chain.filter(exchange)
.then(Mono.fromRunnable(() -> {
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
logger.info("=== 请求结束 ===");
logger.info("响应状态: {}", exchange.getResponse().getStatusCode());
logger.info("处理时间: {}ms", duration);
logger.info("时间: {}", LocalDateTime.now().format(formatter));
logger.info("================\n");
}));
}
@Override
public int getOrder() {
return -200; // 最高优先级,最先执行
}
}
限流过滤器
java
// RateLimitFilter.java
package com.example.gateway.filter;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import reactor.core.publisher.Mono;
import java.nio.charset.StandardCharsets;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;
@Component
public class RateLimitFilter extends AbstractGatewayFilterFactory<RateLimitFilter.Config> {
public RateLimitFilter() {
super(Config.class);
}
@Override
public GatewayFilter apply(Config config) {
return (exchange, chain) -> {
String key = getClientKey(exchange);
if (isAllowed(key, config)) {
return chain.filter(exchange);
} else {
return tooManyRequests(exchange);
}
};
}
private String getClientKey(ServerWebExchange exchange) {
// 基于IP地址的限流
String clientIp = exchange.getRequest().getRemoteAddress() != null ?
exchange.getRequest().getRemoteAddress().getAddress().getHostAddress() : "unknown";
return "rate_limit:" + clientIp;
}
private boolean isAllowed(String key, Config config) {
// 这里应该使用Redis实现分布式限流
// 简化实现,使用内存计数器
AtomicInteger counter = counters.get(key);
if (counter == null) {
counter = new AtomicInteger(0);
counters.put(key, counter);
}
long now = System.currentTimeMillis();
if (now - lastResetTime.get() > config.getTimeWindow()) {
counter.set(0);
lastResetTime.set(now);
}
return counter.incrementAndGet() <= config.getMaxRequests();
}
private Mono<Void> tooManyRequests(ServerWebExchange exchange) {
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
String message = "{\"error\":\"请求过于频繁,请稍后重试\",\"code\":\"RATE_LIMIT_EXCEEDED\"}";
DataBuffer buffer = response.bufferFactory().wrap(message.getBytes(StandardCharsets.UTF_8));
return response.writeWith(Mono.just(buffer));
}
// 内存计数器(实际项目中应该使用Redis)
private static final java.util.Map<String, AtomicInteger> counters = new java.util.concurrent.ConcurrentHashMap<>();
private static final AtomicLong lastResetTime = new AtomicLong(System.currentTimeMillis());
public static class Config {
private int maxRequests = 100;
private long timeWindow = 60000; // 1分钟
public int getMaxRequests() { return maxRequests; }
public void setMaxRequests(int maxRequests) { this.maxRequests = maxRequests; }
public long getTimeWindow() { return timeWindow; }
public void setTimeWindow(long timeWindow) { this.timeWindow = timeWindow; }
}
}
✅ 第三部分:网关路由管理(90分钟)
1. 动态路由配置
路由配置管理
java
// RouteConfigManager.java
package com.example.gateway.route;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.route.RouteDefinition;
import org.springframework.cloud.gateway.route.RouteDefinitionWriter;
import org.springframework.stereotype.Service;
import reactor.core.publisher.Mono;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@Service
public class RouteConfigManager {
@Autowired
private RouteDefinitionWriter routeDefinitionWriter;
private final Map<String, RouteDefinition> routeCache = new ConcurrentHashMap<>();
/**
* 添加路由
*/
public Mono<Void> addRoute(RouteDefinition routeDefinition) {
routeCache.put(routeDefinition.getId(), routeDefinition);
return routeDefinitionWriter.save(Mono.just(routeDefinition));
}
/**
* 更新路由
*/
public Mono<Void> updateRoute(RouteDefinition routeDefinition) {
routeCache.put(routeDefinition.getId(), routeDefinition);
return routeDefinitionWriter.save(Mono.just(routeDefinition));
}
/**
* 删除路由
*/
public Mono<Void> deleteRoute(String routeId) {
routeCache.remove(routeId);
return routeDefinitionWriter.delete(Mono.just(routeId));
}
/**
* 获取所有路由
*/
public List<RouteDefinition> getAllRoutes() {
return routeCache.values().stream().toList();
}
/**
* 根据ID获取路由
*/
public RouteDefinition getRouteById(String routeId) {
return routeCache.get(routeId);
}
/**
* 刷新路由
*/
public Mono<Void> refreshRoutes() {
// 清除所有路由
routeCache.values().forEach(route ->
routeDefinitionWriter.delete(Mono.just(route.getId())));
// 重新添加所有路由
return Mono.when(
routeCache.values().stream()
.map(routeDefinitionWriter::save)
.map(mono -> mono.then())
.toList()
);
}
}
路由配置实体
java
// RouteConfig.java
package com.example.gateway.route;
import java.util.List;
import java.util.Map;
public class RouteConfig {
private String id;
private String name;
private String description;
private String uri;
private List<String> predicates;
private List<FilterConfig> filters;
private int order;
private boolean enabled;
private Map<String, Object> metadata;
// 构造函数
public RouteConfig() {}
public RouteConfig(String id, String name, String uri) {
this.id = id;
this.name = name;
this.uri = uri;
this.enabled = true;
}
// Getter和Setter方法
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 String getUri() { return uri; }
public void setUri(String uri) { this.uri = uri; }
public List<String> getPredicates() { return predicates; }
public void setPredicates(List<String> predicates) { this.predicates = predicates; }
public List<FilterConfig> getFilters() { return filters; }
public void setFilters(List<FilterConfig> filters) { this.filters = filters; }
public int getOrder() { return order; }
public void setOrder(int order) { this.order = order; }
public boolean isEnabled() { return enabled; }
public void setEnabled(boolean enabled) { this.enabled = enabled; }
public Map<String, Object> getMetadata() { return metadata; }
public void setMetadata(Map<String, Object> metadata) { this.metadata = metadata; }
public static class FilterConfig {
private String name;
private Map<String, Object> args;
public FilterConfig() {}
public FilterConfig(String name, Map<String, Object> args) {
this.name = name;
this.args = args;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Map<String, Object> getArgs() { return args; }
public void setArgs(Map<String, Object> args) { this.args = args; }
}
}
2. 路由管理控制器
路由管理Controller
java
// RouteManagementController.java
package com.example.gateway.controller;
import com.example.gateway.route.RouteConfig;
import com.example.gateway.route.RouteConfigManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
@RestController
@RequestMapping("/api/gateway/routes")
public class RouteManagementController {
@Autowired
private RouteConfigManager routeConfigManager;
/**
* 获取所有路由配置
*/
@GetMapping
public ResponseEntity<List<RouteConfig>> getAllRoutes() {
List<RouteConfig> routes = routeConfigManager.getAllRoutes();
return ResponseEntity.ok(routes);
}
/**
* 根据ID获取路由配置
*/
@GetMapping("/{routeId}")
public ResponseEntity<RouteConfig> getRouteById(@PathVariable String routeId) {
RouteConfig route = routeConfigManager.getRouteById(routeId);
if (route != null) {
return ResponseEntity.ok(route);
} else {
return ResponseEntity.notFound().build();
}
}
/**
* 创建新路由
*/
@PostMapping
public ResponseEntity<Void> createRoute(@RequestBody RouteConfig routeConfig) {
try {
routeConfigManager.addRoute(convertToRouteDefinition(routeConfig));
return ResponseEntity.ok().build();
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
/**
* 更新路由配置
*/
@PutMapping("/{routeId}")
public ResponseEntity<Void> updateRoute(@PathVariable String routeId,
@RequestBody RouteConfig routeConfig) {
try {
routeConfig.setId(routeId);
routeConfigManager.updateRoute(convertToRouteDefinition(routeConfig));
return ResponseEntity.ok().build();
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
/**
* 删除路由
*/
@DeleteMapping("/{routeId}")
public ResponseEntity<Void> deleteRoute(@PathVariable String routeId) {
try {
routeConfigManager.deleteRoute(routeId);
return ResponseEntity.ok().build();
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
/**
* 启用/禁用路由
*/
@PatchMapping("/{routeId}/status")
public ResponseEntity<Void> updateRouteStatus(@PathVariable String routeId,
@RequestParam boolean enabled) {
try {
RouteConfig route = routeConfigManager.getRouteById(routeId);
if (route != null) {
route.setEnabled(enabled);
routeConfigManager.updateRoute(convertToRouteDefinition(route));
return ResponseEntity.ok().build();
} else {
return ResponseEntity.notFound().build();
}
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
/**
* 刷新所有路由
*/
@PostMapping("/refresh")
public ResponseEntity<Void> refreshRoutes() {
try {
routeConfigManager.refreshRoutes();
return ResponseEntity.ok().build();
} catch (Exception e) {
return ResponseEntity.internalServerError().build();
}
}
/**
* 获取路由统计信息
*/
@GetMapping("/stats")
public ResponseEntity<Map<String, Object>> getRouteStats() {
List<RouteConfig> routes = routeConfigManager.getAllRoutes();
long totalRoutes = routes.size();
long enabledRoutes = routes.stream().filter(RouteConfig::isEnabled).count();
long disabledRoutes = totalRoutes - enabledRoutes;
Map<String, Object> stats = Map.of(
"totalRoutes", totalRoutes,
"enabledRoutes", enabledRoutes,
"disabledRoutes", disabledRoutes
);
return ResponseEntity.ok(stats);
}
/**
* 将RouteConfig转换为RouteDefinition
*/
private org.springframework.cloud.gateway.route.RouteDefinition convertToRouteDefinition(RouteConfig config) {
// 这里需要实现转换逻辑
// 简化实现,实际项目中需要完整的转换
return new org.springframework.cloud.gateway.route.RouteDefinition();
}
}
✅ 第四部分:网关监控与聚合(60分钟)
1. 网关监控配置
监控配置类
java
// GatewayMonitoringConfig.java
package com.example.gateway.config;
import io.micrometer.core.instrument.MeterRegistry;
import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
import org.springframework.boot.actuate.trace.http.InMemoryHttpTraceRepository;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class GatewayMonitoringConfig {
@Bean
public HttpTraceRepository httpTraceRepository() {
return new InMemoryHttpTraceRepository();
}
@Bean
public MeterRegistry meterRegistry() {
return io.micrometer.core.instrument.Metrics.globalRegistry;
}
}
2. 服务聚合
用户信息聚合服务
java
// UserInfoAggregationService.java
package com.example.gateway.service;
import com.example.gateway.dto.UserInfoDTO;
import com.example.gateway.dto.OrderSummaryDTO;
import com.example.gateway.dto.ProductHistoryDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.reactive.function.client.WebClient;
import reactor.core.publisher.Mono;
import java.util.List;
@Service
public class UserInfoAggregationService {
@Autowired
private WebClient.Builder webClientBuilder;
/**
* 聚合用户完整信息
*/
public Mono<UserInfoDTO> aggregateUserInfo(Long userId) {
return Mono.zip(
getUserBasicInfo(userId),
getUserOrders(userId),
getUserProductHistory(userId)
).map(tuple -> {
UserInfoDTO userInfo = tuple.getT1();
userInfo.setOrderSummary(tuple.getT2());
userInfo.setProductHistory(tuple.getT3());
return userInfo;
});
}
/**
* 获取用户基本信息
*/
private Mono<UserInfoDTO> getUserBasicInfo(Long userId) {
return webClientBuilder.build()
.get()
.uri("http://user-service/api/users/{userId}", userId)
.retrieve()
.bodyToMono(UserInfoDTO.class);
}
/**
* 获取用户订单摘要
*/
private Mono<OrderSummaryDTO> getUserOrders(Long userId) {
return webClientBuilder.build()
.get()
.uri("http://order-service/api/orders/user/{userId}/summary", userId)
.retrieve()
.bodyToMono(OrderSummaryDTO.class);
}
/**
* 获取用户商品历史
*/
private Mono<ProductHistoryDTO> getUserProductHistory(Long userId) {
return webClientBuilder.build()
.get()
.uri("http://product-service/api/products/user/{userId}/history", userId)
.retrieve()
.bodyToMono(ProductHistoryDTO.class);
}
}
聚合数据DTO
java
// UserInfoDTO.java
package com.example.gateway.dto;
import java.time.LocalDateTime;
import java.util.List;
public class UserInfoDTO {
private Long id;
private String username;
private String email;
private String firstName;
private String lastName;
private String phone;
private Boolean enabled;
private LocalDateTime createdAt;
private OrderSummaryDTO orderSummary;
private ProductHistoryDTO productHistory;
// 构造函数
public UserInfoDTO() {}
// Getter和Setter方法
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 String getFirstName() { return firstName; }
public void setFirstName(String firstName) { this.firstName = firstName; }
public String getLastName() { return lastName; }
public void setLastName(String lastName) { this.lastName = lastName; }
public String getPhone() { return phone; }
public void setPhone(String phone) { this.phone = phone; }
public Boolean getEnabled() { return enabled; }
public void setEnabled(Boolean enabled) { this.enabled = enabled; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
public OrderSummaryDTO getOrderSummary() { return orderSummary; }
public void setOrderSummary(OrderSummaryDTO orderSummary) { this.orderSummary = orderSummary; }
public ProductHistoryDTO getProductHistory() { return productHistory; }
public void setProductHistory(ProductHistoryDTO productHistory) { this.productHistory = productHistory; }
public static class OrderSummaryDTO {
private Long totalOrders;
private Double totalAmount;
private List<RecentOrderDTO> recentOrders;
public Long getTotalOrders() { return totalOrders; }
public void setTotalOrders(Long totalOrders) { this.totalOrders = totalOrders; }
public Double getTotalAmount() { return totalAmount; }
public void setTotalAmount(Double totalAmount) { this.totalAmount = totalAmount; }
public List<RecentOrderDTO> getRecentOrders() { return recentOrders; }
public void setRecentOrders(List<RecentOrderDTO> recentOrders) { this.recentOrders = recentOrders; }
}
public static class ProductHistoryDTO {
private Long totalProducts;
private List<RecentProductDTO> recentProducts;
public Long getTotalProducts() { return totalProducts; }
public void setTotalProducts(Long totalProducts) { this.totalProducts = totalProducts; }
public List<RecentProductDTO> getRecentProducts() { return recentProducts; }
public void setRecentProducts(List<RecentProductDTO> recentProducts) { this.recentProducts = recentProducts; }
}
public static class RecentOrderDTO {
private Long id;
private String orderNumber;
private Double amount;
private String status;
private LocalDateTime createdAt;
// Getter和Setter方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getOrderNumber() { return orderNumber; }
public void setOrderNumber(String orderNumber) { this.orderNumber = orderNumber; }
public Double getAmount() { return amount; }
public void setAmount(Double amount) { this.amount = amount; }
public String getStatus() { return status; }
public void setStatus(String status) { this.status = status; }
public LocalDateTime getCreatedAt() { return createdAt; }
public void setCreatedAt(LocalDateTime createdAt) { this.createdAt = createdAt; }
}
public static class RecentProductDTO {
private Long id;
private String name;
private String category;
private LocalDateTime lastViewed;
// Getter和Setter方法
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getCategory() { return category; }
public void setCategory(String category) { this.category = category; }
public LocalDateTime getLastViewed() { return lastViewed; }
public void setLastViewed(LocalDateTime lastViewed) { this.lastViewed = lastViewed; }
}
}
🎯 今日学习总结
1. 掌握的核心技能
- ✅ API网关架构设计
- ✅ Spring Cloud Gateway配置
- ✅ 自定义过滤器开发
- ✅ 动态路由管理
- ✅ 服务聚合与监控
2. 网关核心功能
- 路由转发:智能路由到不同微服务
- 安全认证:统一的权限控制
- 限流熔断:保护后端服务
- 日志监控:统一的请求追踪
- 服务聚合:减少客户端请求
3. Spring Cloud Gateway特点
- 高性能:基于WebFlux响应式编程
- 灵活配置:支持动态路由配置
- 丰富过滤器:内置多种过滤器
- 监控完善:集成Actuator监控
- 扩展性强:支持自定义过滤器
4. 下一步学习方向
- 分布式事务管理
- 服务监控与追踪
- 容器化部署
- 微服务测试策略
- 性能优化与调优
学习建议
- 架构理解:深入理解网关在微服务架构中的作用
- 过滤器开发:学会开发自定义过滤器处理通用逻辑
- 路由管理:掌握动态路由配置和管理
- 性能优化:理解网关性能瓶颈和优化策略
- 监控运维:学会使用监控工具分析网关性能