瀏覽代碼

update version
remove zuul
add spring gateway

Mr.qian 2 天之前
父節點
當前提交
cfa984cb6b

+ 118 - 68
pom.xml

@@ -17,7 +17,7 @@
     <parent>
     <parent>
         <groupId>org.springframework.boot</groupId>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-parent</artifactId>
         <artifactId>spring-boot-starter-parent</artifactId>
-        <version>2.0.5.RELEASE</version>
+        <version>2.7.18</version>
     </parent>
     </parent>
 
 
     <dependencies>
     <dependencies>
@@ -86,21 +86,18 @@
         </dependency>
         </dependency>
 
 
         <dependency>
         <dependency>
-            <groupId>org.springframework.cloud</groupId>
+            <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
             <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+            <version>2.2.9.RELEASE</version>
         </dependency>
         </dependency>
 
 
         <dependency>
         <dependency>
-            <groupId>org.springframework.cloud</groupId>
+            <groupId>com.alibaba.cloud</groupId>
             <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
             <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+            <version>2.2.9.RELEASE</version>
         </dependency>
         </dependency>
 
 
         <!--redis依赖-->
         <!--redis依赖-->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-redis</artifactId>
-            <version>1.3.8.RELEASE</version>
-        </dependency>
         <dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-jdbc</artifactId>
             <artifactId>spring-boot-starter-jdbc</artifactId>
@@ -111,20 +108,25 @@
             <scope>test</scope>
             <scope>test</scope>
         </dependency>
         </dependency>
 
 
-        <dependency>
-            <groupId>org.springframework.cloud</groupId>
-            <artifactId>spring-cloud-starter-zipkin</artifactId>
-        </dependency>
+        <!-- <dependency> -->
+        <!--     <groupId>org.springframework.cloud</groupId> -->
+        <!--     <artifactId>spring-cloud-starter-zipkin</artifactId> -->
+        <!--     <version>2.1.7.RELEASE</version> -->
+        <!-- </dependency> -->
 
 
+        <!--
         <dependency>
         <dependency>
             <groupId>org.springframework.cloud</groupId>
             <groupId>org.springframework.cloud</groupId>
             <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
             <artifactId>spring-cloud-starter-netflix-zuul</artifactId>
+            <version>2.2.10.RELEASE</version>
         </dependency>
         </dependency>
 
 
         <dependency>
         <dependency>
             <groupId>com.netflix.zuul</groupId>
             <groupId>com.netflix.zuul</groupId>
             <artifactId>zuul-core</artifactId>
             <artifactId>zuul-core</artifactId>
+            <version>1.3.1</version>
         </dependency>
         </dependency>
+        -->
 
 
         <!--常用库依赖-->
         <!--常用库依赖-->
         <dependency>
         <dependency>
@@ -136,28 +138,29 @@
             <artifactId>commons-lang3</artifactId>
             <artifactId>commons-lang3</artifactId>
             <version>3.5</version>
             <version>3.5</version>
         </dependency>
         </dependency>
-<!--        <dependency>-->
-<!--            <groupId>com.google.guava</groupId>-->
-<!--            <artifactId>guava</artifactId>-->
-<!--            <version>18.0</version>-->
-<!--        </dependency>-->
-        <dependency>
-		    <groupId>javax.servlet</groupId>
-		    <artifactId>javax.servlet-api</artifactId>
-		    <version>3.1.0</version>
-		    <scope>provided</scope>
-		</dependency>
+        <!--        <dependency>-->
+        <!--            <groupId>com.google.guava</groupId>-->
+        <!--            <artifactId>guava</artifactId>-->
+        <!--            <version>18.0</version>-->
+        <!--        </dependency>-->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <version>3.1.0</version>
+            <scope>provided</scope>
+        </dependency>
         <!--MySQL JDBC驱动-->
         <!--MySQL JDBC驱动-->
         <dependency>
         <dependency>
             <groupId>mysql</groupId>
             <groupId>mysql</groupId>
             <artifactId>mysql-connector-java</artifactId>
             <artifactId>mysql-connector-java</artifactId>
+            <version>8.0.33</version>
             <scope>runtime</scope>
             <scope>runtime</scope>
         </dependency>
         </dependency>
         <!--MyBatis 及 插件依赖-->
         <!--MyBatis 及 插件依赖-->
         <dependency>
         <dependency>
             <groupId>org.mybatis</groupId>
             <groupId>org.mybatis</groupId>
             <artifactId>mybatis-spring</artifactId>
             <artifactId>mybatis-spring</artifactId>
-<!--            <version>1.3.1</version>-->
+            <!--            <version>1.3.1</version>-->
             <version>2.0.1</version>
             <version>2.0.1</version>
         </dependency>
         </dependency>
         <dependency>
         <dependency>
@@ -179,7 +182,7 @@
         <dependency>
         <dependency>
             <groupId>com.alibaba</groupId>
             <groupId>com.alibaba</groupId>
             <artifactId>fastjson</artifactId>
             <artifactId>fastjson</artifactId>
-<!--            <version>1.2.22</version>-->
+            <!--            <version>1.2.22</version>-->
             <version>1.2.58</version>
             <version>1.2.58</version>
         </dependency>
         </dependency>
 
 
@@ -201,6 +204,7 @@
         <dependency>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
             <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-spring-boot-starter</artifactId>
             <artifactId>dubbo-spring-boot-starter</artifactId>
+            <version>3.0.10</version>
         </dependency>
         </dependency>
 
 
         <dependency>
         <dependency>
@@ -218,56 +222,82 @@
         <dependency>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
             <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo</artifactId>
             <artifactId>dubbo</artifactId>
+            <version>3.0.10</version>
         </dependency>
         </dependency>
 
 
-        <!-- Dubbo Registry Nacos -->
         <dependency>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
             <groupId>org.apache.dubbo</groupId>
-            <artifactId>dubbo-registry-nacos</artifactId>
-            <version>2.7.1</version>
+            <artifactId>dubbo-serialization-kryo</artifactId>
+            <version>2.7.9</version>
         </dependency>
         </dependency>
 
 
+        <!-- Dubbo Registry Nacos -->
         <dependency>
         <dependency>
-            <groupId>com.alibaba.nacos</groupId>
-            <artifactId>nacos-client</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>com.google.guava</groupId>
-                    <artifactId>guava</artifactId>
-                </exclusion>
-            </exclusions>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-registry-nacos</artifactId>
+            <version>3.0.10</version>
         </dependency>
         </dependency>
 
 
+        <!-- <dependency> -->
+        <!--     <groupId>com.alibaba.nacos</groupId> -->
+        <!--     <artifactId>nacos-client</artifactId> -->
+        <!--     <exclusions> -->
+        <!--         <exclusion> -->
+        <!--             <groupId>com.google.guava</groupId> -->
+        <!--             <artifactId>guava</artifactId> -->
+        <!--         </exclusion> -->
+        <!--     </exclusions> -->
+        <!-- </dependency> -->
+
         <!-- swagger2 -->
         <!-- swagger2 -->
-        <dependency>
-            <groupId>io.springfox</groupId>
-            <artifactId>springfox-swagger2</artifactId>
-            <version>2.9.2</version>
-        </dependency>
-        <dependency>
-            <groupId>io.springfox</groupId>
-            <artifactId>springfox-swagger-ui</artifactId>
-            <version>2.9.2</version>
-        </dependency>
-        <dependency>
-            <groupId>com.github.xiaoymin</groupId>
-            <artifactId>swagger-bootstrap-ui</artifactId>
-            <version>1.8.5</version>
-        </dependency>
+        <!-- <dependency> -->
+        <!--     <groupId>io.springfox</groupId> -->
+        <!--     <artifactId>springfox-swagger2</artifactId> -->
+        <!--     <version>2.9.2</version> -->
+        <!-- </dependency> -->
+        <!-- <dependency> -->
+        <!--     <groupId>io.springfox</groupId> -->
+        <!--     <artifactId>springfox-swagger-ui</artifactId> -->
+        <!--     <version>2.9.2</version> -->
+        <!-- </dependency> -->
+        <!-- <dependency> -->
+        <!--     <groupId>com.github.xiaoymin</groupId> -->
+        <!--     <artifactId>swagger-bootstrap-ui</artifactId> -->
+        <!--     <version>1.8.5</version> -->
+        <!-- </dependency> -->
 
 
         <!-- swagger2 皮肤 -->
         <!-- swagger2 皮肤 -->
+        <!-- <dependency> -->
+        <!--     <groupId>com.github.caspar-chen</groupId> -->
+        <!--     <artifactId>swagger-ui-layer</artifactId> -->
+        <!--     <version>1.1.2</version> -->
+        <!-- </dependency> -->
+
+
+        <!-- <dependency> -->
+        <!--     <groupId>com.spring4all</groupId> -->
+        <!--     <artifactId>swagger-spring-boot-starter</artifactId> -->
+        <!--     <version>1.8.0.RELEASE</version> -->
+        <!--     <scope>compile</scope> -->
+        <!-- </dependency> -->
+
         <dependency>
         <dependency>
-            <groupId>com.github.caspar-chen</groupId>
-            <artifactId>swagger-ui-layer</artifactId>
-            <version>1.1.2</version>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
         </dependency>
         </dependency>
 
 
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.13.2</version>
+            <scope>test</scope>
+        </dependency>
 
 
         <dependency>
         <dependency>
-            <groupId>com.spring4all</groupId>
-            <artifactId>swagger-spring-boot-starter</artifactId>
-            <version>1.8.0.RELEASE</version>
-            <scope>compile</scope>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-ui</artifactId>
+            <version>1.6.14</version>
         </dependency>
         </dependency>
 
 
         <dependency>
         <dependency>
@@ -280,6 +310,26 @@
             <artifactId>lombok</artifactId>
             <artifactId>lombok</artifactId>
         </dependency>
         </dependency>
 
 
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-gateway</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-circuitbreaker-reactor-resilience4j</artifactId>
+        </dependency>
+
+
     </dependencies>
     </dependencies>
 
 
     <dependencyManagement>
     <dependencyManagement>
@@ -287,26 +337,26 @@
             <dependency>
             <dependency>
                 <groupId>org.springframework.cloud</groupId>
                 <groupId>org.springframework.cloud</groupId>
                 <artifactId>spring-cloud-dependencies</artifactId>
                 <artifactId>spring-cloud-dependencies</artifactId>
-                <version>Finchley.SR1</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-            <dependency>
-                <groupId>org.springframework.cloud</groupId>
-                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
-                <version>0.2.2.RELEASE</version>
+                <version>2021.0.8</version>
                 <type>pom</type>
                 <type>pom</type>
                 <scope>import</scope>
                 <scope>import</scope>
             </dependency>
             </dependency>
+            <!-- <dependency> -->
+            <!--     <groupId>com.alibaba.cloud</groupId> -->
+            <!--     <artifactId>spring-cloud-alibaba-dependencies</artifactId> -->
+            <!--     <version>2021.0.5.0</version> -->
+            <!--     <type>pom</type> -->
+            <!--     <scope>import</scope> -->
+            <!-- </dependency> -->
         </dependencies>
         </dependencies>
     </dependencyManagement>
     </dependencyManagement>
     <build>
     <build>
-       <plugins>
+        <plugins>
             <plugin>
             <plugin>
                 <groupId>org.springframework.boot</groupId>
                 <groupId>org.springframework.boot</groupId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <artifactId>spring-boot-maven-plugin</artifactId>
                 <configuration>
                 <configuration>
-                	<finalName>gateway</finalName>
+                    <finalName>gateway</finalName>
                 </configuration>
                 </configuration>
             </plugin>
             </plugin>
             <plugin>
             <plugin>

+ 32 - 54
src/main/java/com/txz/project/GatewayApplication.java

@@ -1,34 +1,29 @@
 package com.txz.project;
 package com.txz.project;
 
 
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.core.util.StrUtil;
-import com.spring4all.swagger.EnableSwagger2Doc;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.boot.builder.SpringApplicationBuilder;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
 import org.springframework.cloud.client.discovery.EnableDiscoveryClient;
-import org.springframework.cloud.netflix.zuul.EnableZuulProxy;
-import org.springframework.cloud.netflix.zuul.filters.discovery.PatternServiceRouteMapper;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.cloud.openfeign.EnableFeignClients;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Primary;
 import org.springframework.context.annotation.Primary;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
 import org.springframework.web.cors.CorsConfiguration;
 import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.cors.reactive.CorsWebFilter;
+import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource;
 import org.springframework.web.filter.CorsFilter;
 import org.springframework.web.filter.CorsFilter;
-import springfox.documentation.swagger.web.SwaggerResource;
-import springfox.documentation.swagger.web.SwaggerResourcesProvider;
 
 
 import java.util.ArrayList;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.List;
 
 
 
 
-@EnableZuulProxy
+//@EnableZuulProxy
 @EnableDiscoveryClient
 @EnableDiscoveryClient
 @SpringBootApplication
 @SpringBootApplication
 @EnableFeignClients
 @EnableFeignClients
-@EnableSwagger2Doc
 public class GatewayApplication extends SpringBootServletInitializer {
 public class GatewayApplication extends SpringBootServletInitializer {
 
 
     @Value("${swagger.resource}")
     @Value("${swagger.resource}")
@@ -43,54 +38,37 @@ public class GatewayApplication extends SpringBootServletInitializer {
         SpringApplication.run(GatewayApplication.class, args);
         SpringApplication.run(GatewayApplication.class, args);
     }
     }
 
 
-	@Bean
-	public PatternServiceRouteMapper serviceRouteMapper() {
-		return new PatternServiceRouteMapper(
-				"(?<name>^.+)-(?<version>v.+$)",
-				"${version}/${name}");
-	}
+    @Bean
+    public CorsWebFilter corsWebFilter() {
+        CorsConfiguration config = new CorsConfiguration();
+        config.setAllowCredentials(true);
+        config.addAllowedOriginPattern("*");
+        config.addAllowedHeader("*");
+        config.setMaxAge(18000L);
+        config.addAllowedMethod("*");
 
 
-    @Component
-    @Primary
-    class DocumentationConfig implements SwaggerResourcesProvider {
-        @Override
-        public List<SwaggerResource> get() {
-            List resources = new ArrayList<>();
-            resources.add(swaggerResource("gateway", "/v2/api-docs", "1.0"));
-            if (StrUtil.isNotBlank(swaggerResource)){
-                for (String resource:swaggerResource.split(",")) {
-                    resources.add(swaggerResource(resource, "/"+resource+"/v2/api-docs", "1.0"));
-                }
-            }
-            return resources;
-        }
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", config);
 
 
-        private SwaggerResource swaggerResource(String name, String location, String version) {
-            SwaggerResource swaggerResource = new SwaggerResource();
-            swaggerResource.setName(name);
-            swaggerResource.setLocation(location);
-            swaggerResource.setSwaggerVersion(version);
-            return swaggerResource;
-        }
+        return new CorsWebFilter(source);
     }
     }
 
 
-    @Bean
-    public CorsFilter corsFilter() {
-        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
-        final CorsConfiguration config = new CorsConfiguration();
-        config.setAllowCredentials(true); // 允许cookies跨域
-        config.addAllowedOrigin("*");// 允许向该服务器提交请求的URI,*表示全部允许。。这里尽量限制来源域,比如http://xxxx:8080 ,以降低安全风险。。
-        config.addAllowedHeader("*");// 允许访问的头信息,*表示全部
-        config.setMaxAge(18000L);// 预检请求的缓存时间(秒),即在这个时间段里,对于相同的跨域请求不会再预检了
-        config.addAllowedMethod("*");// 允许提交请求的方法,*表示全部允许,也可以单独设置GET、PUT等
-        config.addAllowedMethod("HEAD");
-        config.addAllowedMethod("GET");// 允许Get的请求方法
-        config.addAllowedMethod("PUT");
-        config.addAllowedMethod("POST");
-        config.addAllowedMethod("DELETE");
-        config.addAllowedMethod("PATCH");
-        source.registerCorsConfiguration("/**", config);
-        return new CorsFilter(source);
-    }
+    // @Bean
+    // public CorsFilter corsFilter() {
+    //     final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+    //     final CorsConfiguration config = new CorsConfiguration();
+    //     config.setAllowCredentials(true);
+    //     config.addAllowedOriginPattern("*");
+    //     config.addAllowedHeader("*");
+    //     config.setMaxAge(18000L);
+    //     config.addAllowedMethod("*");
+    //     config.addAllowedMethod("HEAD");
+    //     config.addAllowedMethod("GET");
+    //     config.addAllowedMethod("PUT");
+    //     config.addAllowedMethod("POST");
+    //     config.addAllowedMethod("DELETE");
+    //     config.addAllowedMethod("PATCH");
+    //     source.registerCorsConfiguration("/**", config);
+    //     return new CorsFilter(source);
+    // }
 }
 }
-

+ 65 - 65
src/main/java/com/txz/project/configurer/ApiFallbackProvider.java

@@ -1,67 +1,67 @@
 package com.txz.project.configurer;
 package com.txz.project.configurer;
 
 
-import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatus;
-import org.springframework.http.MediaType;
-import org.springframework.http.client.ClientHttpResponse;
-import org.springframework.stereotype.Component;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-/**
- * @author: linjie
- * @description:错误拦截回显,熔断
- * @create: 2018/10/11 20:01
- */
-@Component
-public class ApiFallbackProvider implements FallbackProvider{
-
-    @Override
-    public String getRoute() {
-        //设置熔断的服务名
-        //如果是所有服务则设置为*
-        return "*";
-    }
-
-    @Override
-    public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
-        return new ClientHttpResponse() {
-            @Override
-            public HttpStatus getStatusCode() throws IOException {
-                return HttpStatus.OK;
-            }
-
-            @Override
-            public int getRawStatusCode() throws IOException {
-                return 200;
-            }
-
-            @Override
-            public String getStatusText() throws IOException {
-                return "{code:0,message:service error =_=}";
-            }
-
-            @Override
-            public void close() {
-
-            }
-
-            @Override
-            public InputStream getBody() throws IOException {
-                return new ByteArrayInputStream("{\"code\":\"599\",\"message\":\"zuul Access Filter - The service is unavailable.\"}".getBytes());
-            }
-
-            @Override
-            public HttpHeaders getHeaders() {
-                HttpHeaders headers = new HttpHeaders();
-                headers.setContentType(MediaType.APPLICATION_JSON);
-                return headers;
-            }
-        };
-    }
-
-
-}
+// import org.springframework.cloud.netflix.zuul.filters.route.FallbackProvider;
+// import org.springframework.http.HttpHeaders;
+// import org.springframework.http.HttpStatus;
+// import org.springframework.http.MediaType;
+// import org.springframework.http.client.ClientHttpResponse;
+// import org.springframework.stereotype.Component;
+//
+// import java.io.ByteArrayInputStream;
+// import java.io.IOException;
+// import java.io.InputStream;
+//
+// /**
+//  * @author: linjie
+//  * @description:错误拦截回显,熔断
+//  * @create: 2018/10/11 20:01
+//  */
+// @Component
+// public class ApiFallbackProvider implements FallbackProvider{
+//
+//     @Override
+//     public String getRoute() {
+//         //设置熔断的服务名
+//         //如果是所有服务则设置为*
+//         return "*";
+//     }
+//
+//     @Override
+//     public ClientHttpResponse fallbackResponse(String route, Throwable cause) {
+//         return new ClientHttpResponse() {
+//             @Override
+//             public HttpStatus getStatusCode() throws IOException {
+//                 return HttpStatus.OK;
+//             }
+//
+//             @Override
+//             public int getRawStatusCode() throws IOException {
+//                 return 200;
+//             }
+//
+//             @Override
+//             public String getStatusText() throws IOException {
+//                 return "{code:0,message:service error =_=}";
+//             }
+//
+//             @Override
+//             public void close() {
+//
+//             }
+//
+//             @Override
+//             public InputStream getBody() throws IOException {
+//                 return new ByteArrayInputStream("{\"code\":\"599\",\"message\":\"zuul Access Filter - The service is unavailable.\"}".getBytes());
+//             }
+//
+//             @Override
+//             public HttpHeaders getHeaders() {
+//                 HttpHeaders headers = new HttpHeaders();
+//                 headers.setContentType(MediaType.APPLICATION_JSON);
+//                 return headers;
+//             }
+//         };
+//     }
+//
+//
+// }

+ 20 - 12
src/main/java/com/txz/project/configurer/CorsConfig.java

@@ -11,16 +11,24 @@ import java.util.Arrays;
 @Configuration
 @Configuration
 public class CorsConfig {
 public class CorsConfig {
 
 
-    @Bean
-    public CorsFilter corsFilter(){
-        final UrlBasedCorsConfigurationSource source=new UrlBasedCorsConfigurationSource();
-        final CorsConfiguration config=new CorsConfiguration();
-        config.setAllowCredentials(true);
-        config.setAllowedHeaders(Arrays.asList("*"));
-        config.setAllowedOrigins(Arrays.asList("*"));  //http:www.a.com
-        config.setAllowedMethods(Arrays.asList("*"));
-        config.setMaxAge(300L);
-        source.registerCorsConfiguration("/",config);
-        return new CorsFilter(source);
-    }
+   // @Bean
+    // public CorsWebFilter corsWebFilter() {
+    //     CorsConfiguration config = new CorsConfiguration();
+    //     config.setAllowCredentials(true);
+    //     config.addAllowedOriginPattern("*");
+    //     config.addAllowedHeader("*");
+    //     config.setMaxAge(18000L);
+    //     config.addAllowedMethod("*");
+    //     config.addAllowedMethod("HEAD");
+    //     config.addAllowedMethod("GET");
+    //     config.addAllowedMethod("PUT");
+    //     config.addAllowedMethod("POST");
+    //     config.addAllowedMethod("DELETE");
+    //     config.addAllowedMethod("PATCH");
+    //
+    //     UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+    //     source.registerCorsConfiguration("/**", config);
+    //
+    //     return new CorsWebFilter(source);
+    // }
 }
 }

+ 52 - 0
src/main/java/com/txz/project/configurer/GatewayFallbackConfiguration.java

@@ -0,0 +1,52 @@
+
+package com.txz.project.configurer;
+
+import org.springframework.cloud.circuitbreaker.resilience4j.ReactiveResilience4JCircuitBreakerFactory;
+import org.springframework.cloud.circuitbreaker.resilience4j.Resilience4JConfigBuilder;
+import org.springframework.cloud.client.circuitbreaker.Customizer;
+import org.springframework.cloud.gateway.filter.factory.FallbackHeadersGatewayFilterFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+import java.time.Duration;
+
+@Configuration
+public class GatewayFallbackConfiguration {
+
+    /**
+     * 配置默认的断路器
+     * @return Customizer
+     */
+    @Bean
+    public Customizer<ReactiveResilience4JCircuitBreakerFactory> defaultCustomizer() {
+        return factory -> factory.configureDefault(id -> new Resilience4JConfigBuilder(id)
+                .circuitBreakerConfig(io.github.resilience4j.circuitbreaker.CircuitBreakerConfig.ofDefaults())
+                .timeLimiterConfig(io.github.resilience4j.timelimiter.TimeLimiterConfig.custom()
+                        .timeoutDuration(Duration.ofSeconds(5))
+                        .build())
+                .build());
+    }
+
+    /**
+     * 默认的 fallback 处理
+     * @param exchange ServerWebExchange
+     * @param ex Throwable
+     * @return Mono<Void>
+     */
+    public Mono<Void> defaultFallback(ServerWebExchange exchange, Throwable ex) {
+        ServerHttpResponse response = exchange.getResponse();
+        response.setStatusCode(HttpStatus.OK);
+        response.getHeaders().add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_JSON_VALUE);
+        
+        String fallbackResponse = "{\"code\":\"599\",\"message\":\"gateway Fallback - The service is unavailable.\"}";
+        byte[] bytes = fallbackResponse.getBytes(StandardCharsets.UTF_8);
+        return response.writeWith(Mono.just(response.bufferFactory().wrap(bytes)));
+    }
+}

+ 33 - 51
src/main/java/com/txz/project/configurer/SwaggerConfig.java

@@ -1,62 +1,44 @@
 package com.txz.project.configurer;
 package com.txz.project.configurer;
 
 
-import io.swagger.annotations.ApiOperation;
+import io.swagger.v3.oas.models.Components;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+import io.swagger.v3.oas.models.parameters.Parameter;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
 import org.springframework.context.annotation.Profile;
-import springfox.documentation.builders.ApiInfoBuilder;
-import springfox.documentation.builders.ParameterBuilder;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.schema.ModelRef;
-import springfox.documentation.service.ApiInfo;
-import springfox.documentation.service.Contact;
-import springfox.documentation.service.Parameter;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spring.web.plugins.Docket;
-import springfox.documentation.swagger2.annotations.EnableSwagger2;
 
 
-import java.util.ArrayList;
-import java.util.List;
 
 
 @Configuration
 @Configuration
-@EnableSwagger2
-@Profile({"dev","test"})
+@Profile({"dev", "test"})
 public class SwaggerConfig {
 public class SwaggerConfig {
-
+    
     @Bean
     @Bean
-    public Docket docket(){
-        //添加header参数
-        List<Parameter> pars = new ArrayList<>();
-        ParameterBuilder ticketPar = new ParameterBuilder();
-        ticketPar.name("token").description("user token")
-                .modelRef(new ModelRef("string")).parameterType("header")
-                .required(false).build(); //header中的ticket参数非必填,传空也可以
-        ticketPar = new ParameterBuilder();
-        ticketPar.name("appCode").description("appCode")
-                .modelRef(new ModelRef("string")).parameterType("header")
-                .required(false).build(); //header中的ticket参数非必填,传空也可以
-
-        pars.add(ticketPar.build());
-        return new Docket(DocumentationType.SWAGGER_2)
-                .globalOperationParameters(pars)
-                .groupName("demo")
-                .apiInfo(getApiInfo())
-                .select()
-                //设置basePackage会将包下的所有被@Api标记类的所有方法作为api
-                .apis(RequestHandlerSelectors.basePackage("com.yiweikeji.dream.web"))
-                //只有标记了@ApiOperation的方法才会暴露出给swagger
-                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
-                .paths(PathSelectors.regex("/api/.*")).build();
+    public OpenAPI customOpenAPI() {
+        return new OpenAPI()
+                .components(new Components()
+                        .addParameters("token", new Parameter()
+                                .name("token")
+                                .description("user token")
+                                .required(false)
+                                .in("header"))
+                        .addParameters("appCode", new Parameter()
+                                .name("appCode")
+                                .description("appCode")
+                                .required(false)
+                                .in("header")))
+                .info(new Info()
+                        .title("API接口文档")
+                        .description("swagger2 demo api")
+                        .version("1.0")
+                        .contact(new Contact()
+                                .name("admin")
+                                .url("http://localhost/swagger-ui.html")
+                                .email("xxx@qq.com"))
+                        .license(new License()
+                                .name("Apache 2.0")
+                                .url("http://localhost/swagger-ui.html")));
     }
     }
-
-    private ApiInfo getApiInfo(){
-        return new ApiInfoBuilder()
-                .title("API接口文档")
-                .description("swagger2 demo api")
-                .termsOfServiceUrl("http://localhost/swagger-ui.html")
-                .version("1.0").contact(new Contact("admin", "http://localhost/swagger-ui.html", "xxx@qq.com"))
-                .build();
-    }
-
-}
+}

+ 401 - 401
src/main/java/com/txz/project/filter/AccessFilter.java

@@ -1,403 +1,403 @@
 package com.txz.project.filter;
 package com.txz.project.filter;
 
 
-import cn.hutool.core.date.DateUtil;
-import cn.hutool.core.util.StrUtil;
-import com.alibaba.fastjson.JSON;
-import com.txz.cif.dto.UserDTO;
-import com.txz.operating.dto.InterfacesDTO;
-import com.txz.operating.result.Result;
-import com.txz.project.dubbo.client.OperatingInterfacesDubboServiceClient;
-import com.txz.project.dubbo.client.UserDubboServiceClient;
-import com.netflix.zuul.ZuulFilter;
-import com.netflix.zuul.context.RequestContext;
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.ExpiredJwtException;
-import io.jsonwebtoken.Jwts;
-import org.apache.commons.codec.digest.DigestUtils;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.tuple.ImmutableTriple;
-import org.apache.commons.lang3.tuple.Triple;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.List;
-
-@Component
-public class AccessFilter extends ZuulFilter {
-
-    private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
-
-    private static final String X_CLIENT_TOKEN_USERID = "x-client-token-userId";
-    private static final String X_CLIENT_TOKEN_OPERATORID = "x-client-token-operatorId";
-
-    private static final String BEARER = "Bearer ";
-
-    /**
-     * jwt token 密钥,主要用于token解析,签名验证
-     */
-    @Value("${spring.security.oauth2.jwt.signingKey}")
-    private static String signingKey = "txz123456";
-
-
-    @Value("${signature}")
-    private String signature;                                        // 是否启用签名
-
-    @Value("${pub.secret}")
-    private String pubSecret;
-
-    @Value("${interfaces.switch}")
-    private String interfacesSwitch;
-
-    @Resource
-    private UserDubboServiceClient userDubboServiceClient;
-
-
-    @Resource
-    private OperatingInterfacesDubboServiceClient operatingInterfacesDubboServiceClient;
-
-    @Override
-    public String filterType() {
-        return "pre";
-    }
-
-    @Override
-    public int filterOrder() {
-        return 0;
-    }
-
-    @Override
-    public boolean shouldFilter() {
-        return true;
-    }
-
-
-//    @Override    public void doFilter(ServletRequest request, ServletResponse response,            FilterChain chain) throws IOException, ServletException {
-//        HttpServletRequest req = (HttpServletRequest) request;
-//        HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(req);        //获得请求参数中的token值
-//         String token = request.getParamter("token");
-//         if(!StringUtils.isEntry(token)){			//如果请求中带有这个参数,则进行过滤加一个header头
-//             requestWrapper.addHeader("tokenr", token);
-//             chain.doFilter(requestWrapper, response); // Goes to default servlet.
-//        }
-//         chain.doFilter(request, response); // Goes to default servlet.
-//           }
-    @Override
-    public Object run() {
-        RequestContext ctx = RequestContext.getCurrentContext();
-        HttpServletRequest request = ctx.getRequest();
-        String token = request.getHeader("token");
-        String servicePath = request.getRequestURI();
-        try {
-            if (StrUtil.endWith(servicePath,"/v2/api-docs")){
-                return null;
-            }
-            if (StrUtil.equals("off",interfacesSwitch)){
-                return null;
-            }
-            Result<InterfacesDTO> interfacesDTOResult = operatingInterfacesDubboServiceClient.detailForGateway(servicePath);
-            if (!StringUtils.equals("200", interfacesDTOResult.getCode())) {
-                ctx.setSendZuulResponse(false);
-                ctx.setResponseStatusCode(200);
-                ctx.setResponseBody("{\"code\":\"512\",\"message\":\"zuul Access Filter -  unknown interfaces :"+servicePath+"\"}");
-                return false;
-            }
-            InterfacesDTO interfacesDTO = interfacesDTOResult.getData();
-            if (interfacesDTO.getStatus() != 1) {
-                ctx.setSendZuulResponse(false);
-                ctx.setResponseStatusCode(200);
-                ctx.setResponseBody("{\"code\":\"513\",\"message\":\"zuul Access Filter -  interfaces status is error\"}");
-                return false;
-            }
-
-            if (interfacesDTO.getAuthorizeType() == 1) {
-                // 登录拦截
-                Triple<Boolean, String, String> tripleUser = getUserIdFromToken(token,request);
-                if(tripleUser.getLeft() == false) {
-                    log.warn("登录认证失败,请求接口:{},请求IP:{},请求token:{},请求参数:{}", request.getRequestURI(),
-                            getIpAddress(request), request.getHeader("token"), JSON.toJSONString(request.getParameterMap()));
-                    // responseResult(response, result);
-                    ctx.setSendZuulResponse(false);
-                    ctx.setResponseStatusCode(200);
-                    ctx.setResponseBody("{\"code\":\"598\",\"message\":\"zuul Access Filter - login validate is false\"}");
-                    return false;
-                }
-                UserDTO user = userDubboServiceClient.getUser(Long.parseLong(tripleUser.getMiddle()));
-                if (user == null){
-                    ctx.setSendZuulResponse(false);
-                    ctx.setResponseStatusCode(200);
-                    ctx.setResponseBody("{\"code\":\"597\",\"message\":\"zuul Access Filter - user is null\"}");
-                    return false;
-                }
-                if (user.getStatus() != 1){
-                    ctx.setSendZuulResponse(false);
-                    ctx.setResponseStatusCode(200);
-                    ctx.setResponseBody("{\"code\":\"596\",\"message\":\"zuul Access Filter - user status is error\"}");
-                    return false;
-                }
-                ctx.addZuulRequestHeader(X_CLIENT_TOKEN_USERID, tripleUser.getMiddle());
-                ctx.addZuulRequestHeader(X_CLIENT_TOKEN_OPERATORID, tripleUser.getRight());
-                try{
-                    userDubboServiceClient.updateLastTime(Long.parseLong(tripleUser.getMiddle()));
-                }catch (Exception e){
-                    log.error("更新最后请求时间异常",e);
-                }
-//                boolean pass = validateLogin(request);
-//                if (!pass) {
-//                    log.warn("登录认证失败,请求接口:{},请求IP:{},请求token:{},请求参数:{}", request.getRequestURI(),
-//                            getIpAddress(request), request.getHeader("token"), JSON.toJSONString(request.getParameterMap()));
-//                    // responseResult(response, result);
-//                    ctx.setSendZuulResponse(false);
-//                    ctx.setResponseStatusCode(200);
-//                    ctx.setResponseBody("{\"code\":\"598\",\"message\":\"zuul Access Filter - login validate is false\"}");
-//                    return false;
-//                }
-            }
-
-//            if (StringUtils.equals("true", signature)) {
-//                // 验证签名
-//                boolean pass = validateSign(request, (String) merchant.get("secret"));
-//                if (!pass) {
-//                    log.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(),
-//                        getIpAddress(request), JSON.toJSONString(request.getParameterMap()));
-//
-//                    Result result = new Result();
-//                    result.setCode(ResultCode.UNAUTHORIZED).setMessage("签名认证失败");
-//                    // responseResult(response, result);
-//                    ctx.setSendZuulResponse(false);
-//                    ctx.setResponseStatusCode(200);
-//                    ctx.setResponseBody("{\"code\":\"597\",\"message\":\"zuul Access Filter - sign validate is false\"}");
-//                    return false;
-//                }
-//            }
-
-//            if (StringUtils.equals("1", i.getMerchantAuthorizeType())) {
-//                // 商户授权
-//                boolean pass = validateMerchantAuthorize(i.getId(),merchantCode);
-//                if (!pass) {
-//                    log.warn("商户认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(),
-//                        getIpAddress(request), JSON.toJSONString(request.getParameterMap()));
-//
-//                    Result result = new Result();
-//                    result.setCode(ResultCode.UNAUTHORIZED).setMessage("商户认证失败");
-//                    // responseResult(response, result);
-//                    ctx.setSendZuulResponse(false);
-//                    ctx.setResponseStatusCode(200);
-//                    ctx.setResponseBody("{\"code\":\"596\",\"message\":\"zuul Access Filter - merchant validate is false\"}");
-//                    return false;
-//                }
-//            }
-            if (interfacesDTO.getReturnCodeTranslate() != null) {
-                if (interfacesDTO.getReturnCodeTranslate() == 1) {
-                    request.setAttribute("returnCodeTranslate", 1);
-                } else {
-                    request.setAttribute("returnCodeTranslate", 0);
-                }
-            } else {
-                request.setAttribute("returnCodeTranslate", 0);
-            }
-        } catch (Exception e) {
-            log.error("异常e:{}", e);
-            ctx.setSendZuulResponse(false);
-            ctx.setResponseStatusCode(200);
-            ctx.setResponseBody("{\"code\":\"599\",\"message\":\"zuul Access Filter - gateway has error\"}");
-            return false;
-        }
-        return null;
-    }
-
-    /**
-     * 提取jwt token中的数据,获取用户id
-     *
-     * @param authentication
-     * @param request
-     * @return
-     */
-    private Triple<Boolean, String, String> getUserIdFromToken(String authentication,
-                                                               HttpServletRequest request) {
-        try {
-            final Claims claims = this.getJwt(authentication);
-            // claims.getExpiration();
-            //  checkt expiration
-            boolean pass = DateUtil.compare(DateUtil.date(),claims.getExpiration()) < 0;
-//            boolean pass = validateLogin(request);
-            if (pass){
-                String userId = claims.get("userId").toString();
-//                String operatorId = claims.get("operatorId").toString();
-                return new ImmutableTriple<Boolean, String, String>(true, userId , null);
-            }
-        } catch (Exception e) {
-            log.error("get userId from token error:{}", e.getMessage());
-        }
-        return new ImmutableTriple<Boolean, String, String>(false,null,null);
-    }
-
-
-    private static Claims getJwt(String jwtToken) {
-        if (jwtToken.startsWith(BEARER)) {
-            jwtToken = StringUtils.substring(jwtToken, BEARER.length());
-        }
-        Claims claims;
-        try {
-            claims = Jwts.parser()  //得到DefaultJwtParser
-                    .setSigningKey(signingKey.getBytes()) //设置签名的秘钥
-                    .parseClaimsJws(jwtToken).getBody();
-        } catch(ExpiredJwtException e) {
-            claims = e.getClaims();
-        }
-
-        return claims;
-    }
-
-
-    public static void main(String[] args) {
-        System.out.printf(getJwt("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzYXdhIiwiZXhwIjoxNjgxMzY2NTg4LCJ1c2VySWQiOjEyLCJvcGVyYXRvcklkIjo5LCJpYXQiOjE2Nzg3NzQ1ODgsImp0aSI6ImQ1ZjM3MmQ4LWM0YzEtNGZkMy05NmNlLTg3MzEyOWM3MDZjNSJ9.XP4ukA_VuOka_Siwe_DRbaYb1jh5TT4XFdz9TvEUBRs")
-                .get("userId").toString());
-    }
-
-
-    /**
-     * 检验入参(命中否决)
-     *
-     * @param i
-     * @param request
-     * @return 返回false 为命中  返回true 为未命中
-     */
-    private boolean validateParameterAuthorize(InterfacesDTO i, HttpServletRequest request) {
-//        if (i == null) {
-//            return true;
-//        }
-//        List<InterfacePmtDTO> pmts = i.getInPmts();
-//        if (pmts == null || pmts.isEmpty()) {
-//            return true;
-//        }
-//        InterfacePmt jsonPmt = null;
-//        for (InterfacePmt interfacePmt : pmts) {
-//            if (interfacePmt.getIsEnable() != null && interfacePmt.getIsEnable() == 0) {
-//                if (interfacePmt.getDataType() == 5) {
-//                    jsonPmt = interfacePmt;
-//                }
-//            }
-//        }
-//        if (jsonPmt == null) {
-//            for (InterfacePmt interfacePmt : pmts) {
-//                if (interfacePmt.getIsEnable() != null && interfacePmt.getIsEnable() == 0) {
-//                    if (StringUtils.equals(interfacePmt.getIsnull(), "1")) {
-//                        if (StringUtils.isBlank(request.getParameter(interfacePmt.getParam()))) {
-//                            log.info("接口入参验证失败:"+interfacePmt.getParam()+"不能为空");
-//                            request.setAttribute("errorMsg", interfacePmt.getParam());
-//                            return false;
-//                        }
-//                    }
-//                }
-//            }
-//        } else {
-//            JSONObject json = null;
-//            try {
-//                json = JSONObject.parseObject(request.getParameter(jsonPmt.getParam()));
-//            } catch (Exception e) {
-//                log.error("接口入参验证失败,json解析失败e:{}",e);
-//                return false;
-//            }
-//            for (InterfacePmt interfacePmt : pmts) {
-//                if (interfacePmt.getIsEnable() != null && interfacePmt.getIsEnable() == 0) {
-//                    if (StringUtils.equals(interfacePmt.getIsnull(), "1")) {
-//                        if (StringUtils.startsWith(interfacePmt.getParam(),jsonPmt.getParam()+".")) {
-//                            String pmtName = interfacePmt.getParam().substring(jsonPmt.getParam().length()+1, interfacePmt.getParam().length());
-//                            if (json.get(pmtName) == null) {
-//                                log.info("接口入参验证失败:"+interfacePmt.getParam()+"不能为空");
-//                                request.setAttribute("errorMsg", interfacePmt.getParam());
-//                                return false;
-//                            }
-//                        } else {
-//                            if (StringUtils.isBlank(request.getParameter(interfacePmt.getParam()))) {
-//                                log.info("接口入参验证失败:"+interfacePmt.getParam()+"不能为空");
-//                                request.setAttribute("errorMsg", interfacePmt.getParam());
-//                                return false;
-//                            }
-//                        }
-//                    }
-//                }
-//            }
-//        }
-        return true;
-    }
-
-    private boolean validateMerchantAuthorize(Integer id, String merchantCode) {
-//        Result findByCode = commonClient.findByCode(id, merchantCode);
-//        if (StringUtils.equals("200", findByCode.getCode())) {
-//            if (findByCode.getData()!= null) {
-//                return true;
-//            }
-//        }
-        return false;
-    }
-
-    /**
-     * 一个简单的登录认证
-     */
-    private boolean validateLogin(HttpServletRequest request) {
-        String token = request.getHeader("token");
-        if (StringUtils.isBlank(token)) {
-            return false;
-        }
-        UserDTO booleanResult = userDubboServiceClient.validateLogin(token);
-        return  booleanResult != null;
-    }
-
-    /**
-     * 一个简单的签名认证,规则: 1. 将请求参数按ascii码排序 2. 拼接为a=value&b=value...这样的字符串(不包含sign)
-     * 3. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较
-     */
-    private boolean validateSign(HttpServletRequest request, String secret) {
-        String requestSign = request.getParameter("sign");// 获得请求签名,如sign=19e907700db7ad91318424a97c54ed57
-        if (StringUtils.isEmpty(requestSign)) {
-            return false;
-        }
-        List<String> keys = new ArrayList<String>(request.getParameterMap().keySet());
-        keys.remove("sign");// 排除sign参数
-        Collections.sort(keys);// 排序
-
-        StringBuilder sb = new StringBuilder();
-        for (String key : keys) {
-            sb.append(key).append("=").append(request.getParameter(key)).append("&");// 拼接字符串
-        }
-        String linkString = sb.toString();
-        linkString = StringUtils.substring(linkString, 0, linkString.length() - 1);// 去除最后一个'&'
-
-        String sign = DigestUtils.md5Hex(linkString + secret + pubSecret);// 混合密钥md5
-
-        return StringUtils.equals(sign, requestSign);// 比较
-    }
-
-    private String getIpAddress(HttpServletRequest request) {
-        String ip = request.getHeader("x-forwarded-for");
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = request.getHeader("Proxy-Client-IP");
-        }
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = request.getHeader("WL-Proxy-Client-IP");
-        }
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = request.getHeader("HTTP_CLIENT_IP");
-        }
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = request.getHeader("HTTP_X_FORWARDED_FOR");
-        }
-        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
-            ip = request.getRemoteAddr();
-        }
-        // 如果是多级代理,那么取第一个ip为客户端ip
-        if (ip != null && ip.indexOf(",") != -1) {
-            ip = ip.substring(0, ip.indexOf(",")).trim();
-        }
-
-        return ip;
-    }
-
-}
+// import cn.hutool.core.date.DateUtil;
+// import cn.hutool.core.util.StrUtil;
+// import com.alibaba.fastjson.JSON;
+// import com.txz.cif.dto.UserDTO;
+// import com.txz.operating.dto.InterfacesDTO;
+// import com.txz.operating.result.Result;
+// import com.txz.project.dubbo.client.OperatingInterfacesDubboServiceClient;
+// import com.txz.project.dubbo.client.UserDubboServiceClient;
+// import com.netflix.zuul.ZuulFilter;
+// import com.netflix.zuul.context.RequestContext;
+// import io.jsonwebtoken.Claims;
+// import io.jsonwebtoken.ExpiredJwtException;
+// import io.jsonwebtoken.Jwts;
+// import org.apache.commons.codec.digest.DigestUtils;
+// import org.apache.commons.lang3.StringUtils;
+// import org.apache.commons.lang3.tuple.ImmutableTriple;
+// import org.apache.commons.lang3.tuple.Triple;
+// import org.slf4j.Logger;
+// import org.slf4j.LoggerFactory;
+// import org.springframework.beans.factory.annotation.Value;
+// import org.springframework.stereotype.Component;
+//
+// import javax.annotation.Resource;
+// import javax.servlet.http.HttpServletRequest;
+// import java.util.ArrayList;
+// import java.util.Collections;
+// import java.util.List;
+//
+// @Component
+// public class AccessFilter extends ZuulFilter {
+//
+//     private static Logger log = LoggerFactory.getLogger(AccessFilter.class);
+//
+//     private static final String X_CLIENT_TOKEN_USERID = "x-client-token-userId";
+//     private static final String X_CLIENT_TOKEN_OPERATORID = "x-client-token-operatorId";
+//
+//     private static final String BEARER = "Bearer ";
+//
+//     /**
+//      * jwt token 密钥,主要用于token解析,签名验证
+//      */
+//     @Value("${spring.security.oauth2.jwt.signingKey}")
+//     private static String signingKey = "txz123456";
+//
+//
+//     @Value("${signature}")
+//     private String signature;                                        // 是否启用签名
+//
+//     @Value("${pub.secret}")
+//     private String pubSecret;
+//
+//     @Value("${interfaces.switch}")
+//     private String interfacesSwitch;
+//
+//     @Resource
+//     private UserDubboServiceClient userDubboServiceClient;
+//
+//
+//     @Resource
+//     private OperatingInterfacesDubboServiceClient operatingInterfacesDubboServiceClient;
+//
+//     @Override
+//     public String filterType() {
+//         return "pre";
+//     }
+//
+//     @Override
+//     public int filterOrder() {
+//         return 0;
+//     }
+//
+//     @Override
+//     public boolean shouldFilter() {
+//         return true;
+//     }
+//
+//
+// //    @Override    public void doFilter(ServletRequest request, ServletResponse response,            FilterChain chain) throws IOException, ServletException {
+// //        HttpServletRequest req = (HttpServletRequest) request;
+// //        HeaderMapRequestWrapper requestWrapper = new HeaderMapRequestWrapper(req);        //获得请求参数中的token值
+// //         String token = request.getParamter("token");
+// //         if(!StringUtils.isEntry(token)){			//如果请求中带有这个参数,则进行过滤加一个header头
+// //             requestWrapper.addHeader("tokenr", token);
+// //             chain.doFilter(requestWrapper, response); // Goes to default servlet.
+// //        }
+// //         chain.doFilter(request, response); // Goes to default servlet.
+// //           }
+//     @Override
+//     public Object run() {
+//         RequestContext ctx = RequestContext.getCurrentContext();
+//         HttpServletRequest request = ctx.getRequest();
+//         String token = request.getHeader("token");
+//         String servicePath = request.getRequestURI();
+//         try {
+//             if (StrUtil.endWith(servicePath,"/v3/api-docs")){
+//                 return null;
+//             }
+//             if (StrUtil.equals("off",interfacesSwitch)){
+//                 return null;
+//             }
+//             Result<InterfacesDTO> interfacesDTOResult = operatingInterfacesDubboServiceClient.detailForGateway(servicePath);
+//             if (!StringUtils.equals("200", interfacesDTOResult.getCode())) {
+//                 ctx.setSendZuulResponse(false);
+//                 ctx.setResponseStatusCode(200);
+//                 ctx.setResponseBody("{\"code\":\"512\",\"message\":\"zuul Access Filter -  unknown interfaces :"+servicePath+"\"}");
+//                 return false;
+//             }
+//             InterfacesDTO interfacesDTO = interfacesDTOResult.getData();
+//             if (interfacesDTO.getStatus() != 1) {
+//                 ctx.setSendZuulResponse(false);
+//                 ctx.setResponseStatusCode(200);
+//                 ctx.setResponseBody("{\"code\":\"513\",\"message\":\"zuul Access Filter -  interfaces status is error\"}");
+//                 return false;
+//             }
+//
+//             if (interfacesDTO.getAuthorizeType() == 1) {
+//                 // 登录拦截
+//                 Triple<Boolean, String, String> tripleUser = getUserIdFromToken(token,request);
+//                 if(tripleUser.getLeft() == false) {
+//                     log.warn("登录认证失败,请求接口:{},请求IP:{},请求token:{},请求参数:{}", request.getRequestURI(),
+//                             getIpAddress(request), request.getHeader("token"), JSON.toJSONString(request.getParameterMap()));
+//                     // responseResult(response, result);
+//                     ctx.setSendZuulResponse(false);
+//                     ctx.setResponseStatusCode(200);
+//                     ctx.setResponseBody("{\"code\":\"598\",\"message\":\"zuul Access Filter - login validate is false\"}");
+//                     return false;
+//                 }
+//                 UserDTO user = userDubboServiceClient.getUser(Long.parseLong(tripleUser.getMiddle()));
+//                 if (user == null){
+//                     ctx.setSendZuulResponse(false);
+//                     ctx.setResponseStatusCode(200);
+//                     ctx.setResponseBody("{\"code\":\"597\",\"message\":\"zuul Access Filter - user is null\"}");
+//                     return false;
+//                 }
+//                 if (user.getStatus() != 1){
+//                     ctx.setSendZuulResponse(false);
+//                     ctx.setResponseStatusCode(200);
+//                     ctx.setResponseBody("{\"code\":\"596\",\"message\":\"zuul Access Filter - user status is error\"}");
+//                     return false;
+//                 }
+//                 ctx.addZuulRequestHeader(X_CLIENT_TOKEN_USERID, tripleUser.getMiddle());
+//                 ctx.addZuulRequestHeader(X_CLIENT_TOKEN_OPERATORID, tripleUser.getRight());
+//                 try{
+//                     userDubboServiceClient.updateLastTime(Long.parseLong(tripleUser.getMiddle()));
+//                 }catch (Exception e){
+//                     log.error("更新最后请求时间异常",e);
+//                 }
+// //                boolean pass = validateLogin(request);
+// //                if (!pass) {
+// //                    log.warn("登录认证失败,请求接口:{},请求IP:{},请求token:{},请求参数:{}", request.getRequestURI(),
+// //                            getIpAddress(request), request.getHeader("token"), JSON.toJSONString(request.getParameterMap()));
+// //                    // responseResult(response, result);
+// //                    ctx.setSendZuulResponse(false);
+// //                    ctx.setResponseStatusCode(200);
+// //                    ctx.setResponseBody("{\"code\":\"598\",\"message\":\"zuul Access Filter - login validate is false\"}");
+// //                    return false;
+// //                }
+//             }
+//
+// //            if (StringUtils.equals("true", signature)) {
+// //                // 验证签名
+// //                boolean pass = validateSign(request, (String) merchant.get("secret"));
+// //                if (!pass) {
+// //                    log.warn("签名认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(),
+// //                        getIpAddress(request), JSON.toJSONString(request.getParameterMap()));
+// //
+// //                    Result result = new Result();
+// //                    result.setCode(ResultCode.UNAUTHORIZED).setMessage("签名认证失败");
+// //                    // responseResult(response, result);
+// //                    ctx.setSendZuulResponse(false);
+// //                    ctx.setResponseStatusCode(200);
+// //                    ctx.setResponseBody("{\"code\":\"597\",\"message\":\"zuul Access Filter - sign validate is false\"}");
+// //                    return false;
+// //                }
+// //            }
+//
+// //            if (StringUtils.equals("1", i.getMerchantAuthorizeType())) {
+// //                // 商户授权
+// //                boolean pass = validateMerchantAuthorize(i.getId(),merchantCode);
+// //                if (!pass) {
+// //                    log.warn("商户认证失败,请求接口:{},请求IP:{},请求参数:{}", request.getRequestURI(),
+// //                        getIpAddress(request), JSON.toJSONString(request.getParameterMap()));
+// //
+// //                    Result result = new Result();
+// //                    result.setCode(ResultCode.UNAUTHORIZED).setMessage("商户认证失败");
+// //                    // responseResult(response, result);
+// //                    ctx.setSendZuulResponse(false);
+// //                    ctx.setResponseStatusCode(200);
+// //                    ctx.setResponseBody("{\"code\":\"596\",\"message\":\"zuul Access Filter - merchant validate is false\"}");
+// //                    return false;
+// //                }
+// //            }
+//             if (interfacesDTO.getReturnCodeTranslate() != null) {
+//                 if (interfacesDTO.getReturnCodeTranslate() == 1) {
+//                     request.setAttribute("returnCodeTranslate", 1);
+//                 } else {
+//                     request.setAttribute("returnCodeTranslate", 0);
+//                 }
+//             } else {
+//                 request.setAttribute("returnCodeTranslate", 0);
+//             }
+//         } catch (Exception e) {
+//             log.error("异常e:{}", e);
+//             ctx.setSendZuulResponse(false);
+//             ctx.setResponseStatusCode(200);
+//             ctx.setResponseBody("{\"code\":\"599\",\"message\":\"zuul Access Filter - gateway has error\"}");
+//             return false;
+//         }
+//         return null;
+//     }
+//
+//     /**
+//      * 提取jwt token中的数据,获取用户id
+//      *
+//      * @param authentication
+//      * @param request
+//      * @return
+//      */
+//     private Triple<Boolean, String, String> getUserIdFromToken(String authentication,
+//                                                                HttpServletRequest request) {
+//         try {
+//             final Claims claims = this.getJwt(authentication);
+//             // claims.getExpiration();
+//             //  checkt expiration
+//             boolean pass = DateUtil.compare(DateUtil.date(),claims.getExpiration()) < 0;
+// //            boolean pass = validateLogin(request);
+//             if (pass){
+//                 String userId = claims.get("userId").toString();
+// //                String operatorId = claims.get("operatorId").toString();
+//                 return new ImmutableTriple<Boolean, String, String>(true, userId , null);
+//             }
+//         } catch (Exception e) {
+//             log.error("get userId from token error:{}", e.getMessage());
+//         }
+//         return new ImmutableTriple<Boolean, String, String>(false,null,null);
+//     }
+//
+//
+//     private static Claims getJwt(String jwtToken) {
+//         if (jwtToken.startsWith(BEARER)) {
+//             jwtToken = StringUtils.substring(jwtToken, BEARER.length());
+//         }
+//         Claims claims;
+//         try {
+//             claims = Jwts.parser()  //得到DefaultJwtParser
+//                     .setSigningKey(signingKey.getBytes()) //设置签名的秘钥
+//                     .parseClaimsJws(jwtToken).getBody();
+//         } catch(ExpiredJwtException e) {
+//             claims = e.getClaims();
+//         }
+//
+//         return claims;
+//     }
+//
+//
+//     public static void main(String[] args) {
+//         System.out.printf(getJwt("eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzYXdhIiwiZXhwIjoxNjgxMzY2NTg4LCJ1c2VySWQiOjEyLCJvcGVyYXRvcklkIjo5LCJpYXQiOjE2Nzg3NzQ1ODgsImp0aSI6ImQ1ZjM3MmQ4LWM0YzEtNGZkMy05NmNlLTg3MzEyOWM3MDZjNSJ9.XP4ukA_VuOka_Siwe_DRbaYb1jh5TT4XFdz9TvEUBRs")
+//                 .get("userId").toString());
+//     }
+//
+//
+//     /**
+//      * 检验入参(命中否决)
+//      *
+//      * @param i
+//      * @param request
+//      * @return 返回false 为命中  返回true 为未命中
+//      */
+//     private boolean validateParameterAuthorize(InterfacesDTO i, HttpServletRequest request) {
+// //        if (i == null) {
+// //            return true;
+// //        }
+// //        List<InterfacePmtDTO> pmts = i.getInPmts();
+// //        if (pmts == null || pmts.isEmpty()) {
+// //            return true;
+// //        }
+// //        InterfacePmt jsonPmt = null;
+// //        for (InterfacePmt interfacePmt : pmts) {
+// //            if (interfacePmt.getIsEnable() != null && interfacePmt.getIsEnable() == 0) {
+// //                if (interfacePmt.getDataType() == 5) {
+// //                    jsonPmt = interfacePmt;
+// //                }
+// //            }
+// //        }
+// //        if (jsonPmt == null) {
+// //            for (InterfacePmt interfacePmt : pmts) {
+// //                if (interfacePmt.getIsEnable() != null && interfacePmt.getIsEnable() == 0) {
+// //                    if (StringUtils.equals(interfacePmt.getIsnull(), "1")) {
+// //                        if (StringUtils.isBlank(request.getParameter(interfacePmt.getParam()))) {
+// //                            log.info("接口入参验证失败:"+interfacePmt.getParam()+"不能为空");
+// //                            request.setAttribute("errorMsg", interfacePmt.getParam());
+// //                            return false;
+// //                        }
+// //                    }
+// //                }
+// //            }
+// //        } else {
+// //            JSONObject json = null;
+// //            try {
+// //                json = JSONObject.parseObject(request.getParameter(jsonPmt.getParam()));
+// //            } catch (Exception e) {
+// //                log.error("接口入参验证失败,json解析失败e:{}",e);
+// //                return false;
+// //            }
+// //            for (InterfacePmt interfacePmt : pmts) {
+// //                if (interfacePmt.getIsEnable() != null && interfacePmt.getIsEnable() == 0) {
+// //                    if (StringUtils.equals(interfacePmt.getIsnull(), "1")) {
+// //                        if (StringUtils.startsWith(interfacePmt.getParam(),jsonPmt.getParam()+".")) {
+// //                            String pmtName = interfacePmt.getParam().substring(jsonPmt.getParam().length()+1, interfacePmt.getParam().length());
+// //                            if (json.get(pmtName) == null) {
+// //                                log.info("接口入参验证失败:"+interfacePmt.getParam()+"不能为空");
+// //                                request.setAttribute("errorMsg", interfacePmt.getParam());
+// //                                return false;
+// //                            }
+// //                        } else {
+// //                            if (StringUtils.isBlank(request.getParameter(interfacePmt.getParam()))) {
+// //                                log.info("接口入参验证失败:"+interfacePmt.getParam()+"不能为空");
+// //                                request.setAttribute("errorMsg", interfacePmt.getParam());
+// //                                return false;
+// //                            }
+// //                        }
+// //                    }
+// //                }
+// //            }
+// //        }
+//         return true;
+//     }
+//
+//     private boolean validateMerchantAuthorize(Integer id, String merchantCode) {
+// //        Result findByCode = commonClient.findByCode(id, merchantCode);
+// //        if (StringUtils.equals("200", findByCode.getCode())) {
+// //            if (findByCode.getData()!= null) {
+// //                return true;
+// //            }
+// //        }
+//         return false;
+//     }
+//
+//     /**
+//      * 一个简单的登录认证
+//      */
+//     private boolean validateLogin(HttpServletRequest request) {
+//         String token = request.getHeader("token");
+//         if (StringUtils.isBlank(token)) {
+//             return false;
+//         }
+//         UserDTO booleanResult = userDubboServiceClient.validateLogin(token);
+//         return  booleanResult != null;
+//     }
+//
+//     /**
+//      * 一个简单的签名认证,规则: 1. 将请求参数按ascii码排序 2. 拼接为a=value&b=value...这样的字符串(不包含sign)
+//      * 3. 混合密钥(secret)进行md5获得签名,与请求的签名进行比较
+//      */
+//     private boolean validateSign(HttpServletRequest request, String secret) {
+//         String requestSign = request.getParameter("sign");// 获得请求签名,如sign=19e907700db7ad91318424a97c54ed57
+//         if (StringUtils.isEmpty(requestSign)) {
+//             return false;
+//         }
+//         List<String> keys = new ArrayList<String>(request.getParameterMap().keySet());
+//         keys.remove("sign");// 排除sign参数
+//         Collections.sort(keys);// 排序
+//
+//         StringBuilder sb = new StringBuilder();
+//         for (String key : keys) {
+//             sb.append(key).append("=").append(request.getParameter(key)).append("&");// 拼接字符串
+//         }
+//         String linkString = sb.toString();
+//         linkString = StringUtils.substring(linkString, 0, linkString.length() - 1);// 去除最后一个'&'
+//
+//         String sign = DigestUtils.md5Hex(linkString + secret + pubSecret);// 混合密钥md5
+//
+//         return StringUtils.equals(sign, requestSign);// 比较
+//     }
+//
+//     private String getIpAddress(HttpServletRequest request) {
+//         String ip = request.getHeader("x-forwarded-for");
+//         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+//             ip = request.getHeader("Proxy-Client-IP");
+//         }
+//         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+//             ip = request.getHeader("WL-Proxy-Client-IP");
+//         }
+//         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+//             ip = request.getHeader("HTTP_CLIENT_IP");
+//         }
+//         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+//             ip = request.getHeader("HTTP_X_FORWARDED_FOR");
+//         }
+//         if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+//             ip = request.getRemoteAddr();
+//         }
+//         // 如果是多级代理,那么取第一个ip为客户端ip
+//         if (ip != null && ip.indexOf(",") != -1) {
+//             ip = ip.substring(0, ip.indexOf(",")).trim();
+//         }
+//
+//         return ip;
+//     }
+//
+// }

+ 245 - 0
src/main/java/com/txz/project/filter/AccessGlobalFilter.java

@@ -0,0 +1,245 @@
+package com.txz.project.filter;
+
+import cn.hutool.core.util.StrUtil;
+import com.alibaba.fastjson.JSON;
+import com.txz.cif.dto.UserDTO;
+import com.txz.operating.dto.InterfacesDTO;
+import com.txz.operating.result.Result;
+import com.txz.project.dubbo.client.OperatingInterfacesDubboServiceClient;
+import com.txz.project.dubbo.client.UserDubboServiceClient;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.ExpiredJwtException;
+import io.jsonwebtoken.Jwts;
+import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.tuple.ImmutableTriple;
+import org.apache.commons.lang3.tuple.Triple;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.cloud.gateway.filter.GatewayFilterChain;
+import org.springframework.cloud.gateway.filter.GlobalFilter;
+import org.springframework.core.Ordered;
+import org.springframework.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpRequest;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import javax.annotation.Resource;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * @author: MTD®️
+ * @date: 2025/8/20
+ */
+
+@Component
+public class AccessGlobalFilter implements GlobalFilter, Ordered {
+
+    private static Logger log = LoggerFactory.getLogger(AccessGlobalFilter.class);
+
+    // 自定义请求头名称,用于传递用户ID和操作者ID
+    private static final String X_CLIENT_TOKEN_USERID = "x-client-token-userId";
+    private static final String X_CLIENT_TOKEN_OPERATORID = "x-client-token-operatorId";
+
+    // Bearer token 前缀
+    private static final String BEARER = "Bearer ";
+
+    /**
+     * jwt token 密钥,主要用于token解析,签名验证
+     */
+    @Value("${spring.security.oauth2.jwt.signingKey}")
+    private static String signingKey = "txz123456";  // 默认签名密钥,用于JWT token的解析和验证
+
+
+    @Value("${signature}")
+    private String signature;                                        // 是否启用签名的配置
+
+    @Value("${pub.secret}")
+    private String pubSecret;                                        // 公钥密钥,用于签名验证
+
+    @Value("${interfaces.switch}")
+    private String interfacesSwitch;                                // 接口开关配置,控制是否启用接口访问控制
+
+    @Resource
+    private UserDubboServiceClient userDubboServiceClient;           // 用户服务客户端,用于调用用户相关服务
+
+
+    @Resource
+    private OperatingInterfacesDubboServiceClient operatingInterfacesDubboServiceClient;  // 接口服务客户端,用于获取接口配置信息
+
+    /**
+     * 网关过滤器核心方法,处理每个进入网关的请求
+     * @param exchange 当前请求的上下文信息
+     * @param chain 网关过滤器链
+     * @return 处理结果
+     */
+    @Override
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        ServerHttpRequest request = exchange.getRequest();
+        ServerHttpResponse response = exchange.getResponse();
+        
+        // 从请求头获取token和请求路径
+        String token = request.getHeaders().getFirst("token");
+        String servicePath = request.getURI().getPath();
+        
+        try {
+            // 如果是Swagger文档请求,直接放行
+            if (StrUtil.endWith(servicePath,"/v3/api-docs")){
+                return chain.filter(exchange);
+            }
+            // 如果接口开关关闭,直接放行
+            if (StrUtil.equals("off",interfacesSwitch)){
+                return chain.filter(exchange);
+            }
+            
+            // 查询接口配置信息
+            Result<InterfacesDTO> interfacesDTOResult = operatingInterfacesDubboServiceClient.detailForGateway(servicePath);
+            if (!StringUtils.equals("200", interfacesDTOResult.getCode())) {
+                // 接口不存在,返回错误信息
+                return writeErrorResponse(response, "{\"code\":\"512\",\"message\":\"gateway Access Filter -  unknown interfaces :"+servicePath+"\"}");
+            }
+            
+            InterfacesDTO interfacesDTO = interfacesDTOResult.getData();
+            // 检查接口状态
+            if (interfacesDTO.getStatus() != 1) {
+                return writeErrorResponse(response, "{\"code\":\"513\",\"message\":\"gateway Access Filter -  interfaces status is error\"}");
+            }
+
+            if (interfacesDTO.getAuthorizeType() == 1) {
+                // 登录拦截
+                Triple<Boolean, String, String> tripleUser = getUserIdFromToken(token,request);
+                if(tripleUser.getLeft() == false) {
+                    log.warn("登录认证失败,请求接口:{},请求IP:{},请求token:{},请求参数:{}", request.getURI().getPath(),
+                            getIpAddress(request), token, JSON.toJSONString(request.getQueryParams()));
+                    return writeErrorResponse(response, "{\"code\":\"598\",\"message\":\"gateway Access Filter - login validate is false\"}");
+                }
+                
+                UserDTO user = userDubboServiceClient.getUser(Long.parseLong(tripleUser.getMiddle()));
+                if (user == null){
+                    return writeErrorResponse(response, "{\"code\":\"597\",\"message\":\"gateway Access Filter - user is null\"}");
+                }
+                if (user.getStatus() != 1){
+                    return writeErrorResponse(response, "{\"code\":\"596\",\"message\":\"gateway Access Filter - user status is error\"}");
+                }
+                
+                // 添加请求头
+                ServerHttpRequest mutateRequest = request.mutate()
+                        .header(X_CLIENT_TOKEN_USERID, tripleUser.getMiddle())
+                        .header(X_CLIENT_TOKEN_OPERATORID, tripleUser.getRight())
+                        .build();
+                ServerWebExchange mutateExchange = exchange.mutate().request(mutateRequest).build();
+                
+                try{
+                    userDubboServiceClient.updateLastTime(Long.parseLong(tripleUser.getMiddle()));
+                }catch (Exception e){
+                    log.error("更新最后请求时间异常",e);
+                }
+                
+                if (interfacesDTO.getReturnCodeTranslate() != null) {
+                    mutateExchange.getAttributes().put("returnCodeTranslate", interfacesDTO.getReturnCodeTranslate());
+                } else {
+                    mutateExchange.getAttributes().put("returnCodeTranslate", 0);
+                }
+                
+                return chain.filter(mutateExchange);
+            }
+
+            // 设置返回码转换属性
+            if (interfacesDTO.getReturnCodeTranslate() != null) {
+                exchange.getAttributes().put("returnCodeTranslate", interfacesDTO.getReturnCodeTranslate());
+            } else {
+                exchange.getAttributes().put("returnCodeTranslate", 0);
+            }
+            
+        } catch (Exception e) {
+            log.error("网关处理异常", e);
+            return writeErrorResponse(response, "{\"code\":\"999\",\"message\":\"gateway Access Filter - inner error\"}");
+        }
+        
+        return chain.filter(exchange);
+    }
+
+    @Override
+    public int getOrder() {
+        return 0;
+    }
+
+    private Mono<Void> writeErrorResponse(ServerHttpResponse response, String errorMessage) {
+        response.setStatusCode(HttpStatus.OK);
+        response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
+        byte[] datas = errorMessage.getBytes(StandardCharsets.UTF_8);
+        DataBuffer buffer = response.bufferFactory().wrap(datas);
+        return response.writeWith(Mono.just(buffer));
+    }
+
+    /**
+     * 从token中获取用户信息
+     *
+     * @param token
+     * @param request
+     * @return
+     */
+    private Triple<Boolean, String, String> getUserIdFromToken(String token, ServerHttpRequest request) {
+        try {
+            if (StringUtils.isBlank(token)) {
+                return new ImmutableTriple<>(false, "", "");
+            }
+            if (token.startsWith(BEARER)) {
+                token = token.substring(6);
+            }
+            Claims claims = Jwts.parser().setSigningKey(signingKey).parseClaimsJws(token).getBody();
+            String userId = (String) claims.get("userId");
+            String operatorId = (String) claims.get("operatorId");
+            return new ImmutableTriple<>(true, userId, operatorId);
+        } catch (ExpiredJwtException eje) {
+            log.error("= = = = = = = = = = = = = = = token已过期:{} = = = = = = = = = = = = = = ", token);
+            return new ImmutableTriple<>(false, "", "");
+        } catch (Exception e) {
+            log.error("= = = = = = = = = = = = = = = token解析失败:{} = = = = = = = = = = = = = = ", token);
+            return new ImmutableTriple<>(false, "", "");
+        }
+    }
+
+    /**
+     * 获取Ip地址
+     * @param request
+     * @return
+     */
+    private String getIpAddress(ServerHttpRequest request) {
+        HttpHeaders headers = request.getHeaders();
+        String ip = headers.getFirst("x-forwarded-for");
+        if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {
+            // 多次反向代理后会有多个ip值,第一个ip才是真实ip
+            if (ip.contains(",")) {
+                ip = ip.split(",")[0];
+            }
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("HTTP_CLIENT_IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("HTTP_X_FORWARDED_FOR");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = headers.getFirst("X-Real-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
+            ip = request.getRemoteAddress().getAddress().getHostAddress();
+        }
+        return ip;
+    }
+}

+ 24 - 28
src/main/java/com/txz/project/filter/ErrorFilter.java

@@ -1,44 +1,40 @@
+
 package com.txz.project.filter;
 package com.txz.project.filter;
 
 
-import com.netflix.zuul.ZuulFilter;
-import com.netflix.zuul.context.RequestContext;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 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.HttpStatus;
 import org.springframework.stereotype.Component;
 import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
 
 
-import javax.servlet.http.HttpServletResponse;
-
-/**
- * 捕获为处理的异常统一做一些处理,让`SendErrorFilter`可以正确的返回异常信息
- */
 @Component
 @Component
-public class ErrorFilter extends ZuulFilter {
+public class ErrorFilter implements GlobalFilter, Ordered {
 
 
     Logger log = LoggerFactory.getLogger(ErrorFilter.class);
     Logger log = LoggerFactory.getLogger(ErrorFilter.class);
 
 
     @Override
     @Override
-    public String filterType() {
-        return "error";
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        // 在 Gateway 中,错误处理通常通过 WebExceptionHandler 来处理
+        // 这里我们采用 try-catch 的方式捕获异常
+        return chain.filter(exchange).onErrorResume(throwable -> {
+            log.error("this is a ErrorFilter : {}", throwable);
+            
+            // 将错误信息存储在 exchange attributes 中
+            exchange.getAttributes().put("error.status_code", HttpStatus.INTERNAL_SERVER_ERROR.value());
+            exchange.getAttributes().put("error.exception", throwable.getCause());
+            
+            // 可以选择返回一个自定义的错误响应
+            // 但通常在 Gateway 中,我们会使用统一的异常处理机制
+            throw new RuntimeException(throwable);
+        });
     }
     }
 
 
     @Override
     @Override
-    public int filterOrder() {
+    public int getOrder() {
         return 10;
         return 10;
     }
     }
-
-    @Override
-    public boolean shouldFilter() {
-        return true;
-    }
-
-    @Override
-    public Object run() {
-        RequestContext ctx = RequestContext.getCurrentContext();
-        Throwable throwable = RequestContext.getCurrentContext().getThrowable();
-        log.error("this is a ErrorFilter : {}", throwable);
-        ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-        ctx.set("error.exception", throwable.getCause());
-        return null;
-    }
-
-}
+}

+ 40 - 0
src/main/java/com/txz/project/filter/ErrorGlobalFilter.java

@@ -0,0 +1,40 @@
+package com.txz.project.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.core.io.buffer.DataBuffer;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+
+@Component
+public class ErrorGlobalFilter implements GlobalFilter, Ordered {
+
+    Logger log = LoggerFactory.getLogger(ErrorGlobalFilter.class);
+
+    @Override
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        return chain.filter(exchange).onErrorResume(e -> {
+            log.error("网关异常处理", e);
+            ServerHttpResponse response = exchange.getResponse();
+            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
+            response.getHeaders().add("Content-Type", "application/json;charset=UTF-8");
+            String errorMessage = "{\"code\":\"999\",\"message\":\"gateway Error Filter - inner error\"}";
+            byte[] datas = errorMessage.getBytes(StandardCharsets.UTF_8);
+            DataBuffer buffer = response.bufferFactory().wrap(datas);
+            return response.writeWith(Mono.just(buffer));
+        });
+    }
+
+    @Override
+    public int getOrder() {
+        return -1; // 最先执行的过滤器之一
+    }
+}

+ 71 - 0
src/main/java/com/txz/project/filter/GatewayErrorWebExceptionHandler.java

@@ -0,0 +1,71 @@
+package com.txz.project.filter;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.txz.project.core.Result;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.Order;
+import org.springframework.core.io.buffer.DataBufferFactory;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.MediaType;
+import org.springframework.http.codec.HttpMessageWriter;
+import org.springframework.http.codec.ServerCodecConfigurer;
+import org.springframework.http.server.reactive.ServerHttpResponse;
+import org.springframework.web.reactive.function.BodyInserters;
+import org.springframework.web.reactive.function.server.RequestPredicates;
+import org.springframework.web.reactive.function.server.RouterFunction;
+import org.springframework.web.reactive.function.server.RouterFunctions;
+import org.springframework.web.reactive.function.server.ServerResponse;
+import org.springframework.web.reactive.result.view.ViewResolver;
+import org.springframework.web.server.ResponseStatusException;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+
+@Order(-1)
+@Configuration
+@RequiredArgsConstructor
+public class GatewayErrorWebExceptionHandler implements ErrorWebExceptionHandler {
+    
+    private static final Logger log = LoggerFactory.getLogger(GatewayErrorWebExceptionHandler.class);
+    
+    private final ObjectMapper objectMapper;
+    
+    @Override
+    public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
+        ServerHttpResponse response = exchange.getResponse();
+        
+        if (response.isCommitted()) {
+            return Mono.error(ex);
+        }
+        
+        // header set
+        response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
+        if (ex instanceof ResponseStatusException) {
+            response.setStatusCode(((ResponseStatusException) ex).getStatus());
+        }
+        
+        return response.writeWith(Mono.fromSupplier(() -> {
+            DataBufferFactory bufferFactory = response.bufferFactory();
+            try {
+                log.error("Error rquest :{} Error Spring Cloud Gateway : {}", exchange.getRequest().getPath(),
+                        ex.getMessage());
+                Result result = new Result();
+                result.setCode("500");
+                result.setMessage("server error");
+                return bufferFactory.wrap(objectMapper.writeValueAsBytes(result));
+            } catch (JsonProcessingException e) {
+                log.warn("Error writing response", ex);
+                return bufferFactory.wrap(new byte[0]);
+            }
+        }));
+    }
+}

+ 99 - 99
src/main/java/com/txz/project/filter/PostFilter.java

@@ -1,101 +1,101 @@
 package com.txz.project.filter;
 package com.txz.project.filter;
 
 
-import com.alibaba.fastjson.JSONObject;
-import com.txz.operating.dto.ErrorCodeDTO;
-import com.txz.operating.result.Result;
-import com.txz.project.dubbo.client.OperatingInterfacesDubboServiceClient;
-import com.netflix.zuul.ZuulFilter;
-import com.netflix.zuul.context.RequestContext;
-import org.apache.commons.lang.StringUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Component;
-
-import javax.annotation.Resource;
-import javax.servlet.http.HttpServletRequest;
-import java.io.ByteArrayOutputStream;
-import java.io.InputStream;
-
-/**
- * 捕获为处理的异常统一做一些处理,让`SendErrorFilter`可以正确的返回异常信息
- */
-@Component
-public class PostFilter extends ZuulFilter {
-
-    Logger log = LoggerFactory.getLogger(PostFilter.class);
-
-    @Resource
-    private OperatingInterfacesDubboServiceClient operatingInterfacesDubboServiceClient;
-
-    @Override
-    public String filterType() {
-        return "post";
-    }
-
-    @Override
-    public int filterOrder() {
-        return 10;
-    }
-
-    @Override
-    public boolean shouldFilter() {
-        return true;
-    }
-
-    @Override
-    public Object run() {
-        RequestContext ctx = RequestContext.getCurrentContext();
-        try {
-            HttpServletRequest request = ctx.getRequest();
-//            log.info(String.format("%s AccessTokenFilter request to %s", request.getRequestURI(),
-//                    request.getRequestURL().toString()));
-            Integer returnCodeTranslate = (Integer) request.getAttribute("returnCodeTranslate");
-            if (returnCodeTranslate == null) {
-                return null;
-            }
-            if (returnCodeTranslate == 0) {
-                return null;
-            }
-            InputStream in = ctx.getResponseDataStream();
-            if (in == null) {
-                return null;
-            }
-            ByteArrayOutputStream out = new ByteArrayOutputStream();
-            byte[] buffer = new byte[1024 * 4];
-            int n = 0;
-            while ((n = in.read(buffer)) != -1) {
-                out.write(buffer, 0, n);
-            }
-            String jsonStr = new String(out.toByteArray());
-            JSONObject json = JSONObject.parseObject(jsonStr);
-            if (StringUtils.equals((String) json.get("code"), "200")) {
-                ctx.setSendZuulResponse(true);
-                ctx.setResponseStatusCode(200);
-                ctx.setResponseBody(json.toJSONString());
-                return null;
-            }
-            String service = request.getRequestURI().split("/")[1];
-            Result<ErrorCodeDTO> codeResult = operatingInterfacesDubboServiceClient.getErrorCode(service, String.valueOf(json.get("code")));
-            if (StringUtils.equals("200", codeResult.getCode())) {
-                json.put("code", codeResult.getData().getReturnCode());
-                json.put("data", json.get("data"));
-                json.put("message", codeResult.getData().getReturnMsg());
-                ctx.setSendZuulResponse(true);
-                ctx.setResponseStatusCode(200);
-                ctx.setResponseBody(json.toJSONString());// 输出最终结果
-            } else {
-                ctx.setSendZuulResponse(true);
-                ctx.setResponseStatusCode(200);
-                ctx.setResponseBody(json.toJSONString());
-                return null;
-            }
-        } catch (Exception e) {
-            log.error("错误码转译失败,e{}", e);
-            ctx.setSendZuulResponse(true);
-            ctx.setResponseStatusCode(200);
-            ctx.setResponseBody("{\"code\":\"999\",\"message\":\"inner error code change out error code has exception\"}");// 输出最终结果
-        }
-        return null;
-    }
-
-}
+// import com.alibaba.fastjson.JSONObject;
+// import com.txz.operating.dto.ErrorCodeDTO;
+// import com.txz.operating.result.Result;
+// import com.txz.project.dubbo.client.OperatingInterfacesDubboServiceClient;
+// import com.netflix.zuul.ZuulFilter;
+// import com.netflix.zuul.context.RequestContext;
+// import org.apache.commons.lang.StringUtils;
+// import org.slf4j.Logger;
+// import org.slf4j.LoggerFactory;
+// import org.springframework.stereotype.Component;
+//
+// import javax.annotation.Resource;
+// import javax.servlet.http.HttpServletRequest;
+// import java.io.ByteArrayOutputStream;
+// import java.io.InputStream;
+//
+// /**
+//  * 捕获为处理的异常统一做一些处理,让`SendErrorFilter`可以正确的返回异常信息
+//  */
+// @Component
+// public class PostFilter extends ZuulFilter {
+//
+//     Logger log = LoggerFactory.getLogger(PostFilter.class);
+//
+//     @Resource
+//     private OperatingInterfacesDubboServiceClient operatingInterfacesDubboServiceClient;
+//
+//     @Override
+//     public String filterType() {
+//         return "post";
+//     }
+//
+//     @Override
+//     public int filterOrder() {
+//         return 10;
+//     }
+//
+//     @Override
+//     public boolean shouldFilter() {
+//         return true;
+//     }
+//
+//     @Override
+//     public Object run() {
+//         RequestContext ctx = RequestContext.getCurrentContext();
+//         try {
+//             HttpServletRequest request = ctx.getRequest();
+// //            log.info(String.format("%s AccessTokenFilter request to %s", request.getRequestURI(),
+// //                    request.getRequestURL().toString()));
+//             Integer returnCodeTranslate = (Integer) request.getAttribute("returnCodeTranslate");
+//             if (returnCodeTranslate == null) {
+//                 return null;
+//             }
+//             if (returnCodeTranslate == 0) {
+//                 return null;
+//             }
+//             InputStream in = ctx.getResponseDataStream();
+//             if (in == null) {
+//                 return null;
+//             }
+//             ByteArrayOutputStream out = new ByteArrayOutputStream();
+//             byte[] buffer = new byte[1024 * 4];
+//             int n = 0;
+//             while ((n = in.read(buffer)) != -1) {
+//                 out.write(buffer, 0, n);
+//             }
+//             String jsonStr = new String(out.toByteArray());
+//             JSONObject json = JSONObject.parseObject(jsonStr);
+//             if (StringUtils.equals((String) json.get("code"), "200")) {
+//                 ctx.setSendZuulResponse(true);
+//                 ctx.setResponseStatusCode(200);
+//                 ctx.setResponseBody(json.toJSONString());
+//                 return null;
+//             }
+//             String service = request.getRequestURI().split("/")[1];
+//             Result<ErrorCodeDTO> codeResult = operatingInterfacesDubboServiceClient.getErrorCode(service, String.valueOf(json.get("code")));
+//             if (StringUtils.equals("200", codeResult.getCode())) {
+//                 json.put("code", codeResult.getData().getReturnCode());
+//                 json.put("data", json.get("data"));
+//                 json.put("message", codeResult.getData().getReturnMsg());
+//                 ctx.setSendZuulResponse(true);
+//                 ctx.setResponseStatusCode(200);
+//                 ctx.setResponseBody(json.toJSONString());// 输出最终结果
+//             } else {
+//                 ctx.setSendZuulResponse(true);
+//                 ctx.setResponseStatusCode(200);
+//                 ctx.setResponseBody(json.toJSONString());
+//                 return null;
+//             }
+//         } catch (Exception e) {
+//             log.error("错误码转译失败,e{}", e);
+//             ctx.setSendZuulResponse(true);
+//             ctx.setResponseStatusCode(200);
+//             ctx.setResponseBody("{\"code\":\"999\",\"message\":\"inner error code change out error code has exception\"}");// 输出最终结果
+//         }
+//         return null;
+//     }
+//
+// }

+ 54 - 0
src/main/java/com/txz/project/filter/ResponseGlobalFilter.java

@@ -0,0 +1,54 @@
+package com.txz.project.filter;
+
+import com.alibaba.fastjson.JSONObject;
+import com.txz.operating.dto.ErrorCodeDTO;
+import com.txz.operating.result.Result;
+import com.txz.project.dubbo.client.OperatingInterfacesDubboServiceClient;
+import org.apache.commons.lang.StringUtils;
+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 javax.annotation.Resource;
+
+@Component
+public class ResponseGlobalFilter implements GlobalFilter, Ordered {
+
+    Logger log = LoggerFactory.getLogger(ResponseGlobalFilter.class);
+
+    @Resource
+    private OperatingInterfacesDubboServiceClient operatingInterfacesDubboServiceClient;
+
+    @Override
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
+        return chain.filter(exchange).then(
+                Mono.fromRunnable(() -> {
+                    try {
+                        ServerHttpRequest request = exchange.getRequest();
+                        Integer returnCodeTranslate = exchange.getAttribute("returnCodeTranslate");
+                        if (returnCodeTranslate == null || returnCodeTranslate == 0) {
+                            return;
+                        }
+                        
+                        // 这里可以添加对响应的处理逻辑
+                        // 在 Spring Cloud Gateway 中,修改响应比 Zuul 更复杂,需要使用更高级的技术
+                        // 比如使用 ResponseRewriteGatewayFilterFactory 或自定义的 GatewayFilterFactory
+                        
+                    } catch (Exception e) {
+                        log.error("错误码转译失败", e);
+                    }
+                })
+        );
+    }
+
+    @Override
+    public int getOrder() {
+        return 10;
+    }
+}

+ 32 - 30
src/main/java/com/txz/project/filter/ThrowExceptionFilter.java

@@ -1,47 +1,49 @@
 package com.txz.project.filter;
 package com.txz.project.filter;
 
 
-import com.netflix.zuul.ZuulFilter;
-import com.netflix.zuul.context.RequestContext;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.slf4j.LoggerFactory;
-
-import javax.servlet.http.HttpServletResponse;
-
-//@Component
-public class ThrowExceptionFilter extends ZuulFilter  {
+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.ServerHttpResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.server.ServerWebExchange;
+import reactor.core.publisher.Mono;
+
+@Component
+public class ThrowExceptionFilter implements GlobalFilter, Ordered {
 
 
     private static Logger log = LoggerFactory.getLogger(ThrowExceptionFilter.class);
     private static Logger log = LoggerFactory.getLogger(ThrowExceptionFilter.class);
 
 
     @Override
     @Override
-    public String filterType() {
-        return "pre";
-    }
-
-    @Override
-    public int filterOrder() {
-        return 0;
-    }
-
-    @Override
-    public boolean shouldFilter() {
-        return true;
-    }
-
-    @Override
-    public Object run() {
-        RequestContext ctx = RequestContext.getCurrentContext();
+    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
         try {
         try {
+            // doSomething() 方法原本是用于抛出异常的,这里保留该逻辑
             doSomething();
             doSomething();
+            return chain.filter(exchange);
         } catch (Exception e) {
         } catch (Exception e) {
-            ctx.set("error.status_code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
-            ctx.set("error.exception", e);
-            ctx.set("error.message", "有一些错误发生");
+            log.error("网关处理异常", e);
+            ServerHttpResponse response = exchange.getResponse();
+            response.setStatusCode(HttpStatus.INTERNAL_SERVER_ERROR);
+            
+            // 将异常信息放入 exchange attributes 中,供后续处理使用
+            exchange.getAttributes().put("error.status_code", HttpStatus.INTERNAL_SERVER_ERROR.value());
+            exchange.getAttributes().put("error.exception", e);
+            exchange.getAttributes().put("error.message", "有一些错误发生");
+            
+            // 继续传递给下一个过滤器处理
+            return chain.filter(exchange);
         }
         }
-        return null;
     }
     }
 
 
-    private void doSomething() {
-//        throw new RuntimeException("Exist some errors...");
+    @Override
+    public int getOrder() {
+        return 0;
     }
     }
 
 
+    private void doSomething() {
+        // 原 Zuul filter 中的逻辑,目前是空实现
+        // throw new RuntimeException("Exist some errors...");
+    }
 }
 }

+ 33 - 22
src/main/resources/bootstrap.properties

@@ -12,17 +12,25 @@ test.nacos=172.10.100.40:8848
 pro.nacos=172.10.100.10:30308
 pro.nacos=172.10.100.10:30308
 spring.cloud.nacos.discovery.server-addr=${${spring.profiles.active}.nacos}
 spring.cloud.nacos.discovery.server-addr=${${spring.profiles.active}.nacos}
 spring.cloud.nacos.config.server-addr=${${spring.profiles.active}.nacos}
 spring.cloud.nacos.config.server-addr=${${spring.profiles.active}.nacos}
-spring.cloud.nacos.config.prefix=gateway
-spring.cloud.nacos.config.file-extension=properties
-spring.cloud.nacos.config.ext-config[0].data-id=mq-${spring.profiles.active}.properties
-spring.cloud.nacos.config.ext-config[0].refresh=true
-spring.cloud.nacos.config.ext-config[1].data-id=redis-${spring.profiles.active}.properties
-spring.cloud.nacos.config.ext-config[1].refresh=true
+spring.main.allow-circular-references=true
+springfox.documentation.enabled=false
+#spring.cloud.nacos.config.prefix=gateway-${spring.profiles.active}
+#spring.cloud.nacos.config.file-extension=properties
+#spring.cloud.nacos.config.extension-configs[0]=mq-${spring.profiles.active}.properties
+#spring.cloud.nacos.config.extension-configs[1]=redis-${spring.profiles.active}.properties
+#spring.cloud.nacos.config.ext-config[0].data-id=mq-${spring.profiles.active}.properties
+#spring.cloud.nacos.config.ext-config[0].refresh=true
+#spring.cloud.nacos.config.ext-config[1].data-id=redis-${spring.profiles.active}.properties
+#spring.cloud.nacos.config.ext-config[1].refresh=true
+spring.cloud.nacos.config.extension-configs[0]=mq-${spring.profiles.active}.properties
+spring.cloud.nacos.config.extension-configs[1]=redis-${spring.profiles.active}.properties
+spring.cloud.nacos.config.extension-configs[2]=${spring.application.name}-${spring.profiles.active}.properties
+spring.main.web-application-type=reactive
 dubbo.protocol.serialization=kryo
 dubbo.protocol.serialization=kryo
 dubbo.protocol.optimizer=
 dubbo.protocol.optimizer=
 dubbo.protocol.name=dubbo
 dubbo.protocol.name=dubbo
 dubbo.protocol.port=-1
 dubbo.protocol.port=-1
-dubbo.registry.file=/var/logs/${spring.application.name}/dubbo_${server.port}.cache
+#dubbo.registry.file=/var/logs/${spring.application.name}/dubbo_${server.port}.cache
 
 
 dubbo.registry.address=nacos://${${spring.profiles.active}.nacos}
 dubbo.registry.address=nacos://${${spring.profiles.active}.nacos}
 
 
@@ -35,7 +43,8 @@ dubbo.reference.check=false
 dubbo.consumer.check=false
 dubbo.consumer.check=false
 dubbo.registry.check=false
 dubbo.registry.check=false
 spring.mvc.throw-exception-if-no-handler-found=true
 spring.mvc.throw-exception-if-no-handler-found=true
-spring.resources.add-mappings=true
+spring.web.resources.add-mappings=true
+#spring.resources.add-mappings=true
 multipart.maxFileSize=50Mb
 multipart.maxFileSize=50Mb
 server.undertow.max-http-post-size=83886080
 server.undertow.max-http-post-size=83886080
 spring.servlet.multipart.max-file-size=100MB
 spring.servlet.multipart.max-file-size=100MB
@@ -47,16 +56,22 @@ hystrix.command.default.execution.isolation.thread.timeoutInMilliseconds=30000
 #hystrix.command.default.circuitBreaker.forceClosed=true
 #hystrix.command.default.circuitBreaker.forceClosed=true
 #hystrix.shareSecurityContext=true
 #hystrix.shareSecurityContext=true
 
 
-zuul.ignored-services='*'
-zuul.sensitive-headers=Access-Control-Allow-Origin
-zuul.ignored-headers=Access-Control-Allow-Origin,H-APP-Id,accessToken
+#zuul.ignored-services='*'
+#zuul.sensitive-headers=Access-Control-Allow-Origin
+#zuul.ignored-headers=Access-Control-Allow-Origin,H-APP-Id,accessToken
 
 
+spring.cloud.gateway.discovery.locator.enabled=true
+spring.cloud.gateway.discovery.locator.lower-case-service-id=true
+spring.cloud.gateway.httpclient.connect-timeout=500
+spring.cloud.gateway.httpclient.response-timeout=5000
 
 
-#zuul.routes.api-a.path=/cif/application/**
-#zuul.routes.api-a.service-id=apia
-#zuul.routes.api-a.serviceId=apia
-# 映射具体的url路径
-#zuul.routes.api-a.url=http://192.168.50.98:9031/application/
+spring.cloud.gateway.filter.circuit-breaker.enabled=true
+
+# ?????? - ??????????
+#spring.cloud.gateway.routes[0].id=cif-service
+#spring.cloud.gateway.routes[0].uri=lb://cif
+#spring.cloud.gateway.routes[0].predicates[0]=Path=/cif/**
+#spring.cloud.gateway.routes[0].filters[0]=CircuitBreaker=myCircuitBreaker
 
 
 #apia.ribbon.listOfServers=http://192.168.50.98:9031/application/,http://192.168.50.98:9030/application/
 #apia.ribbon.listOfServers=http://192.168.50.98:9031/application/,http://192.168.50.98:9030/application/
 
 
@@ -65,19 +80,15 @@ hystrix.command.default.circuitBreaker.requestVolumeThreshold=20
 hystrix.command.default.circuitBreaker.errorThresholdPercentage=50%
 hystrix.command.default.circuitBreaker.errorThresholdPercentage=50%
 hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=500
 hystrix.command.default.circuitBreaker.sleepWindowInMilliseconds=500
 #zuul.ignore-security-headers=false
 #zuul.ignore-security-headers=false
-zuul.retryable=true
+#zuul.retryable=true
 ribbon.ConnectTimeout=500
 ribbon.ConnectTimeout=500
 ribbon.ReadTimeout=5000
 ribbon.ReadTimeout=5000
 ribbon.MaxAutoRetries=1
 ribbon.MaxAutoRetries=1
 ribbon.MaxAutoRetriesNextServer=1
 ribbon.MaxAutoRetriesNextServer=1
 #\u8BBE\u7F6E\u5168\u90E8\u8DEF\u7531\u6700\u5927\u4FE1\u53F7\u91CF
 #\u8BBE\u7F6E\u5168\u90E8\u8DEF\u7531\u6700\u5927\u4FE1\u53F7\u91CF
-zuul.semaphore.max-semaphores=5000
+#zuul.semaphore.max-semaphores=5000
 interfaces.switch=off
 interfaces.switch=off
 swagger.resource=cif,operating,backstage,report
 swagger.resource=cif,operating,backstage,report
 
 
 cif.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.BestAvailableRule
 cif.ribbon.NFLoadBalancerRuleClassName=com.netflix.loadbalancer.BestAvailableRule
 spring.security.oauth2.jwt.signingKey=123456
 spring.security.oauth2.jwt.signingKey=123456
-
-
-
-

+ 1 - 1
src/main/resources/logback.xml

@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <?xml version="1.0" encoding="UTF-8"?>
 <configuration debug="false">
 <configuration debug="false">
     <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
     <!--定义日志文件的存储地址 勿在 LogBack 的配置中使用相对路径-->
-    <property name="LOG_HOME" value="/var/logs/gateway" />
+    <property name="LOG_HOME" value="./logs/gateway" />
     <!-- 控制台输出 -->
     <!-- 控制台输出 -->
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
     <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
         <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
         <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">