diff --git a/pom.xml b/pom.xml
index 3e6c2a0..0bc789d 100644
--- a/pom.xml
+++ b/pom.xml
@@ -21,9 +21,87 @@
1.0-SNAPSHOT
- 17
- 17
- UTF-8
+ 17
+ 2.7.18
+ 2021.0.8
+ 2021.1
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-gateway
+ 3.1.8
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-webflux
+ ${spring.boot.version}
+
+
+
+
+ com.alibaba.cloud
+ spring-cloud-starter-alibaba-nacos-discovery
+ ${spring.cloud.alibaba.version}
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-actuator
+ ${spring.boot.version}
+
+
+
+
+ org.projectlombok
+ lombok
+ 1.18.30
+ provided
+
+
+
+ org.springframework.cloud
+ spring-cloud-starter-loadbalancer
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+ ${spring.boot.version}
+
+
+
+ repackage
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.10.1
+
+ ${java.version}
+ ${java.version}
+
+
+
+
+
\ No newline at end of file
diff --git a/xs-server/pom.xml b/xs-server/pom.xml
index 9f93468..b5c4153 100644
--- a/xs-server/pom.xml
+++ b/xs-server/pom.xml
@@ -17,4 +17,12 @@
UTF-8
+
+
+ com.xiang
+ xs-service
+ 1.0-SNAPSHOT
+
+
+
\ No newline at end of file
diff --git a/xs-server/src/main/java/com/xiang/XsGatewayApplication.java b/xs-server/src/main/java/com/xiang/XsGatewayApplication.java
index d230ca3..a0a5692 100644
--- a/xs-server/src/main/java/com/xiang/XsGatewayApplication.java
+++ b/xs-server/src/main/java/com/xiang/XsGatewayApplication.java
@@ -2,12 +2,14 @@ package com.xiang;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.autoconfigure.orm.jpa.HibernateJpaAutoConfiguration;
/**
* @Author: xiang
* @Date: 2025-08-12 17:26
*/
-@SpringBootApplication
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class XsGatewayApplication {
public static void main(String[] args) {
SpringApplication.run(XsGatewayApplication.class, args);
diff --git a/xs-server/src/main/java/com/xiang/xservice/gateway/server/controller/ServiceDiscoveryController.java b/xs-server/src/main/java/com/xiang/xservice/gateway/server/controller/ServiceDiscoveryController.java
new file mode 100644
index 0000000..9499738
--- /dev/null
+++ b/xs-server/src/main/java/com/xiang/xservice/gateway/server/controller/ServiceDiscoveryController.java
@@ -0,0 +1,30 @@
+package com.xiang.xservice.gateway.server.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.cloud.client.discovery.DiscoveryClient;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+@RestController
+public class ServiceDiscoveryController {
+ @Autowired
+ private DiscoveryClient discoveryClient;
+
+ /**
+ * 查看所有注册到 Nacos 的服务
+ */
+ @GetMapping("/services")
+ public List getServices() {
+ return discoveryClient.getServices();
+ }
+
+ /**
+ * 查看某个服务的实例信息
+ */
+ @GetMapping("/services/instances")
+ public Object getServiceInstances(String serviceName) {
+ return discoveryClient.getInstances(serviceName);
+ }
+}
diff --git a/xs-server/src/main/resources/application-local.yml b/xs-server/src/main/resources/application-local.yml
index e69de29..d061a5c 100644
--- a/xs-server/src/main/resources/application-local.yml
+++ b/xs-server/src/main/resources/application-local.yml
@@ -0,0 +1,40 @@
+server:
+ port: 38010
+
+spring:
+ application:
+ name: xservice-gateway
+ main:
+ web-application-type: reactive # 强制使用 WebFlux
+ cloud:
+ nacos:
+ discovery:
+ server-addr: general.xiangtech.xyz:8848
+ namespace: 00131110-3ecb-4a35-8bbb-624edde1d937
+ group: DEFAULT_GROUP
+ username: nacos
+ password: nacos
+ gateway:
+ discovery:
+ locator:
+ enabled: true # 开启 nacos 自动路由
+ routes:
+ - id: xservice-auth-center
+ uri: lb://xservice-auth-center
+ predicates:
+ - Path=/api-auth/**
+ filters:
+ - StripPrefix=1
+
+ redis:
+ host: r-bp1wt59a6nfyt4e3ltpd.redis.rds.aliyuncs.com
+ port: 6379
+ password: Xiang0000 # 如果无密码可以省略
+ database: 0
+ timeout: 5000
+ lettuce:
+ pool:
+ max-active: 8
+ max-idle: 8
+ min-idle: 0
+ max-wait: 1000
\ No newline at end of file
diff --git a/xs-server/src/main/resources/application.yml b/xs-server/src/main/resources/application.yml
index 8258c24..2ad80be 100644
--- a/xs-server/src/main/resources/application.yml
+++ b/xs-server/src/main/resources/application.yml
@@ -3,4 +3,6 @@ server:
spring:
profiles:
- active: local
\ No newline at end of file
+ active: local
+ main:
+ web-application-type: reactive
\ No newline at end of file
diff --git a/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/AuthGlobalFilter.java b/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/AuthGlobalFilter.java
new file mode 100644
index 0000000..92ed0c2
--- /dev/null
+++ b/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/AuthGlobalFilter.java
@@ -0,0 +1,59 @@
+package com.xiang.xservice.gateway.service.core;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+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;
+
+@Slf4j
+@Component
+public class AuthGlobalFilter implements GlobalFilter, Ordered {
+
+ @Override
+ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+ ServerHttpRequest request = exchange.getRequest();
+ String path = request.getURI().getPath();
+ // 放行 /public/** 和 /login
+ if (path.contains("/public/") || path.contains("/login")) {
+ log.debug("跳过 Token 校验: {}", path);
+ return chain.filter(exchange);
+ }
+
+ // 获取 Header 中的 Authorization
+ String token = request.getHeaders().getFirst("Authorization");
+
+ if (!StringUtils.hasText(token)) {
+ log.warn("❌ 缺少 Token: {}", path);
+ exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
+ return exchange.getResponse().setComplete();
+ }
+
+ try {
+ // TODO: 这里换成你自己的 JwtUtil.verify(token)
+// boolean valid = JwtUtil.verify(token);
+ if (false) {
+ log.warn("❌ Token 校验失败: {}", token);
+ exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
+ return exchange.getResponse().setComplete();
+ }
+ } catch (Exception e) {
+ log.error("❌ Token 校验异常", e);
+ exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
+ return exchange.getResponse().setComplete();
+ }
+
+ log.info("✅ Token 校验通过: {}", token);
+ return chain.filter(exchange);
+ }
+
+ @Override
+ public int getOrder() {
+ return -1;
+ }
+}
diff --git a/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/LoggerGlobalFilter.java b/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/LoggerGlobalFilter.java
new file mode 100644
index 0000000..decedc7
--- /dev/null
+++ b/xs-service/src/main/java/com/xiang/xservice/gateway/service/core/LoggerGlobalFilter.java
@@ -0,0 +1,42 @@
+package com.xiang.xservice.gateway.service.core;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.cloud.gateway.route.Route;
+import org.springframework.cloud.gateway.support.ServerWebExchangeUtils;
+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.net.InetSocketAddress;
+
+@Slf4j
+@Component
+public class LoggerGlobalFilter implements GlobalFilter, Ordered {
+ @Override
+ public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+ log.info("🌐 Gateway 请求进入, 原始请求路径:{}", exchange.getRequest().getURI().getPath());
+ ServerHttpRequest request = exchange.getRequest();
+ InetSocketAddress remoteAddress = request.getRemoteAddress();
+ log.info("请求路径: {} | 方法: {} | 来源: {} | 匹配到路由:{}, 转发目标地址:{}",
+ request.getURI(),
+ request.getMethod(),
+ remoteAddress != null ? remoteAddress.getHostString() : "unknown",
+ exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR),
+ exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_REQUEST_URL_ATTR));
+
+ // 继续执行过滤链
+ return chain.filter(exchange)
+ .then(Mono.fromRunnable(() -> {
+ log.info("响应状态: {}", exchange.getResponse().getStatusCode());
+ }));
+ }
+
+ @Override
+ public int getOrder() {
+ return 0;
+ }
+}