diff --git a/api-gateway/pom.xml b/api-gateway/pom.xml new file mode 100644 index 0000000..0cee000 --- /dev/null +++ b/api-gateway/pom.xml @@ -0,0 +1,99 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.6.3 + + + + 3.1.1 + 2.6.3 + ${spring.boot.version} + + api-gateway + + + + org.springframework.cloud + spring-cloud-starter-gateway + ${spring.cloud.version} + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-discovery + 2021.0.1.0 + + + + + com.alibaba.cloud + spring-cloud-starter-alibaba-nacos-config + 2021.0.1.0 + + + + + org.springframework.cloud + spring-cloud-starter-bootstrap + ${spring.cloud.version} + + + org.springframework.cloud + spring-cloud-context + ${spring.cloud.version} + + + org.springframework.cloud + spring-cloud-loadbalancer + ${spring.cloud.version} + + + + org.springframework.boot + spring-boot-starter-actuator + ${spring.boot.version} + + + org.projectlombok + lombok + + + com.alibaba + fastjson + 1.2.83 + compile + + + org.springframework.boot + spring-boot-starter-data-redis-reactive + + + + + org.springframework.boot + spring-boot-starter-security + + + org.aspectj + aspectjweaver + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring.boot.maven.plugin.version} + + + + + \ No newline at end of file diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/GatewayApplication.java b/api-gateway/src/main/java/com/heyu/api/gateway/GatewayApplication.java new file mode 100644 index 0000000..d1a7392 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/GatewayApplication.java @@ -0,0 +1,18 @@ +package com.heyu.api.gateway; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.cloud.client.discovery.EnableDiscoveryClient; + +/** + * https://blog.csdn.net/qq_38380025/article/details/84936466 + */ +@SpringBootApplication +@EnableDiscoveryClient +public class GatewayApplication { + + public static void main(String[] args) { + SpringApplication.run(GatewayApplication.class, args); + } + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/CustomLoadBalancerConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/CustomLoadBalancerConfiguration.java new file mode 100644 index 0000000..21f34b0 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/CustomLoadBalancerConfiguration.java @@ -0,0 +1,30 @@ +package com.heyu.api.gateway.config; + +import com.alibaba.cloud.nacos.discovery.NacosServiceDiscovery; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.loadbalancer.core.CachingServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.env.Environment; + +@Configuration(proxyBeanMethods = false) +@AutoConfigureAfter({CachingServiceInstanceListSupplier.class, NacosServiceDiscovery.class}) +public class CustomLoadBalancerConfiguration { + + + @Bean + ReactorLoadBalancer randomLoadBalancer(Environment environment, + LoadBalancerClientFactory loadBalancerClientFactory) { + String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME); + + //这里返回了我自己定义的方法 + return new MyRandomLoadBalancer(loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name); + + } + + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/GatewayConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/GatewayConfiguration.java new file mode 100644 index 0000000..cf8aa0d --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/GatewayConfiguration.java @@ -0,0 +1,16 @@ +package com.heyu.api.gateway.config; + +import org.springframework.context.annotation.Configuration; + +/** + * XXX + * + * @author weiyachao + * @since 2023/9/22 17:35 + */ +@Configuration +public class GatewayConfiguration { + + + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/GlobalCorsConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/GlobalCorsConfiguration.java new file mode 100644 index 0000000..99fc8d1 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/GlobalCorsConfiguration.java @@ -0,0 +1,41 @@ +package com.heyu.api.gateway.config; + +import com.heyu.api.gateway.config.properties.CorsProperties; +import org.springframework.web.cors.CorsConfiguration; +import org.springframework.web.cors.UrlBasedCorsConfigurationSource; +import org.springframework.web.filter.CorsFilter; + +/** + * 全局跨域配置. + * + */ +// @AutoConfiguration +// @EnableConfigurationProperties(CorsProperties.class) +public class GlobalCorsConfiguration { + + /** + * 允许跨域调用的过滤器. + * + * @param corsProperties 跨域配置 + */ + // @Bean + // @ConditionalOnMissingBean(CorsFilter.class) + public CorsFilter corsFilter(CorsProperties corsProperties) { + CorsConfiguration config = new CorsConfiguration(); + // 设置允许跨域访问的域名 + config.setAllowedOriginPatterns(corsProperties.getAllowedOriginPatterns()); + // 设置允许跨域访问的方法 + config.setAllowedMethods(corsProperties.getAllowedMethods()); + // 设置允许跨域访问的请求头 + config.setAllowedHeaders(corsProperties.getAllowedHeaders()); + config.setExposedHeaders(corsProperties.getExposedHeaders()); + // 允许跨越发送cookie + config.setAllowCredentials(corsProperties.getAllowCredentials()); + config.setMaxAge(corsProperties.getMaxAge()); + + // 对接口配置跨域设置 + UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); + source.registerCorsConfiguration("/**", config); + return new CorsFilter(source); + } +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/MyLoadBalanceAutoConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/MyLoadBalanceAutoConfiguration.java new file mode 100644 index 0000000..c493d5b --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/MyLoadBalanceAutoConfiguration.java @@ -0,0 +1,18 @@ +package com.heyu.api.gateway.config; + +import org.springframework.cloud.loadbalancer.annotation.LoadBalancerClients; + +/** + * + * @author Admin-WPG + * + */ +// https://blog.csdn.net/agulahaha/article/details/130783152 +@LoadBalancerClients(defaultConfiguration = CustomLoadBalancerConfiguration.class) +public class MyLoadBalanceAutoConfiguration { + + + + + +} \ No newline at end of file diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/MyRandomLoadBalancer.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/MyRandomLoadBalancer.java new file mode 100644 index 0000000..660d4cf --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/MyRandomLoadBalancer.java @@ -0,0 +1,93 @@ +package com.heyu.api.gateway.config; + +import com.google.common.collect.Lists; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.springframework.beans.factory.ObjectProvider; +import org.springframework.cloud.client.ServiceInstance; +import org.springframework.cloud.client.loadbalancer.DefaultResponse; +import org.springframework.cloud.client.loadbalancer.EmptyResponse; +import org.springframework.cloud.client.loadbalancer.Request; +import org.springframework.cloud.client.loadbalancer.Response; +import org.springframework.cloud.loadbalancer.core.NoopServiceInstanceListSupplier; +import org.springframework.cloud.loadbalancer.core.ReactorServiceInstanceLoadBalancer; +import org.springframework.cloud.loadbalancer.core.SelectedInstanceCallback; +import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier; +import reactor.core.publisher.Mono; + +import java.util.List; +import java.util.concurrent.ThreadLocalRandom; + +/** + * @author wutao + * @description 自定义负载均衡 + * @date 2021-08-27 + * 自定义实现,就是去实现这个ReactorServiceInstanceLoadBalancer接口。 + * + * 默认实现的随机负载、轮训负载可查看RandomLoadBalancer、RoundRobinLoadBalancer类 + * + */ +public class MyRandomLoadBalancer implements ReactorServiceInstanceLoadBalancer { + + private static final Log log = LogFactory.getLog(MyRandomLoadBalancer.class); + + private final String serviceId; + + private ObjectProvider serviceInstanceListSupplierProvider; + + private final static String DEPLOY_SERVER_IPS = "ips"; + + /** + * @param serviceInstanceListSupplierProvider a provider of + * {@link ServiceInstanceListSupplier} that will be used to get available instances + * @param serviceId id of the service for which to choose an instance + */ + public MyRandomLoadBalancer(ObjectProvider serviceInstanceListSupplierProvider, + String serviceId) { + this.serviceId = serviceId; + this.serviceInstanceListSupplierProvider = serviceInstanceListSupplierProvider; + } + + @SuppressWarnings("rawtypes") + @Override + public Mono> choose(Request request) { + ServiceInstanceListSupplier supplier = serviceInstanceListSupplierProvider + .getIfAvailable(NoopServiceInstanceListSupplier::new); + + return supplier.get(request).next() + .map(serviceInstances -> processInstanceResponse(supplier, serviceInstances)); + } + + private Response processInstanceResponse(ServiceInstanceListSupplier supplier, + List serviceInstances) { + List services = Lists.newArrayList(); + services.addAll(serviceInstances); + for (ServiceInstance server : serviceInstances) { + String hostPost = new StringBuffer(server.getHost()).append("_").append(server.getPort()).toString(); + log.info("MyRandomLoadBalancer hostPost:" + hostPost); + } + + Response serviceInstanceResponse = getInstanceResponse(services); + if (supplier instanceof SelectedInstanceCallback && serviceInstanceResponse.hasServer()) { + ((SelectedInstanceCallback) supplier).selectedServiceInstance(serviceInstanceResponse.getServer()); + } + return serviceInstanceResponse; + } + + + + private Response getInstanceResponse(List instances) { + if (instances.isEmpty()) { + if (log.isWarnEnabled()) { + log.warn("No servers available for service: " + serviceId); + } + return new EmptyResponse(); + } + + int index = ThreadLocalRandom.current().nextInt(instances.size()); + + ServiceInstance instance = instances.get(index); + return new DefaultResponse(instance); + } + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/RedisConfig.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/RedisConfig.java new file mode 100644 index 0000000..de0032b --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/RedisConfig.java @@ -0,0 +1,40 @@ +package com.heyu.api.gateway.config; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.core.StringRedisTemplate; +import org.springframework.data.redis.core.ValueOperations; +import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; + +/** + * Created by wutao on 2019/5/5. + */ +@Configuration +public class RedisConfig { + + @Bean(name={"stringRedisTemplate"}) + public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory factory){ + StringRedisTemplate redisTemplate = new StringRedisTemplate(); + redisTemplate.setConnectionFactory(factory); + return redisTemplate; + } + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate redisTemplate = new RedisTemplate<>(); + redisTemplate.setKeySerializer(new StringRedisSerializer()); + redisTemplate.setHashKeySerializer(new StringRedisSerializer()); + redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer()); + redisTemplate.setConnectionFactory(factory); + return redisTemplate; + } + + @Bean + public ValueOperations valueOperations(RedisTemplate redisTemplate) { + return redisTemplate.opsForValue(); + } +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/SecurityConfig.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/SecurityConfig.java new file mode 100644 index 0000000..9a8d027 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/SecurityConfig.java @@ -0,0 +1,33 @@ +package com.heyu.api.gateway.config; + + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity; +import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity; +import org.springframework.security.config.web.server.ServerHttpSecurity; +import org.springframework.security.web.server.SecurityWebFilterChain; + +@Configuration +@EnableGlobalMethodSecurity(prePostEnabled = true) +@EnableWebFluxSecurity +public class SecurityConfig { + + @Bean + public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity httpSecurity){ + httpSecurity + .authorizeExchange() + //.pathMatchers("/actuator/**").denyAll() + .pathMatchers("/**").permitAll() + .pathMatchers(HttpMethod.OPTIONS).permitAll() + .anyExchange().authenticated() + .and() + .csrf() + .disable() + .cors(); + return httpSecurity.build(); + } +} + + diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/CorsProperties.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/CorsProperties.java new file mode 100644 index 0000000..60c67f3 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/CorsProperties.java @@ -0,0 +1,48 @@ +package com.heyu.api.gateway.config.properties; + +import java.util.List; +import lombok.Getter; +import lombok.Setter; +import org.springframework.boot.context.properties.ConfigurationProperties; + +/** + * 跨域配置. + * + * @author yangning + * @since 2022/11/7 14:45 + */ +@Getter +@Setter +// @ConfigurationProperties(prefix = "application.cors") +public class CorsProperties { + + /** + * 允许跨域访问的域名. + */ + private List allowedOriginPatterns; + + /** + * 允许跨域访问的方法. + */ + private List allowedMethods; + + /** + * 允许跨域访问的请求头. + */ + private List allowedHeaders; + + /** + * 暴露的响应头. + */ + private List exposedHeaders; + + /** + * 是否允许跨域发送cookie. + */ + private Boolean allowCredentials = true; + + /** + * 跨域访问有效期. + */ + private Long maxAge = 1800L; +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/LoadBalanceProperties.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/LoadBalanceProperties.java new file mode 100644 index 0000000..a67c27a --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/LoadBalanceProperties.java @@ -0,0 +1,4 @@ +package com.heyu.api.gateway.config.properties; + +public class LoadBalanceProperties { +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/XssProperties.java b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/XssProperties.java new file mode 100644 index 0000000..be149f3 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/config/properties/XssProperties.java @@ -0,0 +1,41 @@ +package com.heyu.api.gateway.config.properties; + +import java.util.ArrayList; +import java.util.List; +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.stereotype.Component; + +/** + * Xss配置. + * + * @author yangning + * @since 2023/4/7 18:31 + */ +@Data +@Component +@RefreshScope +@ConfigurationProperties(prefix = "security.xss") +public class XssProperties { + + /** + * Xss开关. + */ + private Boolean enabled; + + /** + * 排除路径. + */ + private List excludeUrls = new ArrayList<>(); + + /** + * 访问ip + */ + private String authIP; + + /** + * IP允许访问的url + */ + private List authUrls = new ArrayList<>(); +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/filter/AuthWebFilter.java b/api-gateway/src/main/java/com/heyu/api/gateway/filter/AuthWebFilter.java new file mode 100644 index 0000000..e4ce050 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/filter/AuthWebFilter.java @@ -0,0 +1,265 @@ +package com.heyu.api.gateway.filter; + +import com.alibaba.cloud.commons.lang.StringUtils; +import com.heyu.api.gateway.config.properties.XssProperties; +import com.heyu.api.gateway.util.ApiConstants; +import com.heyu.api.gateway.util.Log4Constans; +import com.heyu.api.gateway.util.OrderUtils; +import com.heyu.api.gateway.util.UserAuthContains; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Publisher; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.io.buffer.DataBuffer; +import org.springframework.core.io.buffer.DataBufferFactory; +import org.springframework.core.io.buffer.DataBufferUtils; +import org.springframework.core.io.buffer.DefaultDataBufferFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.http.server.reactive.ServerHttpRequestDecorator; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.http.server.reactive.ServerHttpResponseDecorator; +import org.springframework.util.CollectionUtils; +import org.springframework.util.ObjectUtils; +import org.springframework.web.server.ServerWebExchange; +import org.springframework.web.server.WebFilter; +import org.springframework.web.server.WebFilterChain; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import reactor.util.context.Context; + +import java.net.InetSocketAddress; +import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.util.List; + +/** + *

+ *

*日志配置 + * @author wulin + * @since 2023-08-07 + * + * https://blog.csdn.net/qq_26274037/article/details/127800559 + */ +@Configuration +@Slf4j +public class AuthWebFilter implements WebFilter { + private static final String UNKNOWN = "unknown"; + private static final String LOCALHOST = "127.0.0.1"; + private static final String SEPARATOR = ","; + + //由nginx配置透传过来 + private static final String HEADER_X_FORWARDED_FOR = "X-Forwarded-For"; + private static final String HEADER_PROXY_CLIENT_IP = "Proxy-Client-IP"; + private static final String HEADER_WL_PROXY_CLIENT_IP = "WL-Proxy-Client-IP"; + + + @Autowired + XssProperties xssProperties; + + + + + @Override + public Mono filter(ServerWebExchange exchange, WebFilterChain chain) { + long startTime = System.currentTimeMillis(); + ServerHttpRequest request = exchange.getRequest(); + String traceId = OrderUtils.getUserPoolOrder(); + String requestId = request.getId();//请求id + MDC.put(Log4Constans.TRACE_ID, traceId); + String url = request.getPath().toString(); + URI URIAll = request.getURI(); + String uri = URIAll.getPath(); + if("/favicon.ico".equals(uri)){ + ServerHttpResponse response = exchange.getResponse(); + DataBuffer bodyDataBuffer = response.bufferFactory().wrap("".getBytes()); + response.getHeaders().add("Content-Type", "application/json;charset=UTF-8"); + return response.writeWith(Mono.just(bodyDataBuffer)); + } + + HttpHeaders httpHeaders = request.getHeaders(); + List paths = httpHeaders.get(ApiConstants.X_FORWARDED_PATH); + String xForwardedPath = null; + if (!CollectionUtils.isEmpty(paths) && uri.equals("/")) { + String path = paths.get(0); + xForwardedPath = path; + } + + String realIpAddress = getRealIpAddress(request); + String m = request.getMethod().toString(); + log.info("AuthWebFilter api start time:{} ip:{} method:{} url:{},uri:{} param:{} headers:{}", + startTime, + realIpAddress, + m, + request.getPath(), + uri, + request.getQueryParams(), + httpHeaders + ); + + if(xssProperties.getEnabled()) { + if (xssProperties.getAuthIP() != null && xssProperties.getAuthIP().contains(realIpAddress)) { + log.info("白名单IP,免验签"); + return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath); + } + if (xssProperties.getExcludeUrls().contains(url)) { + log.info("排除免签url内,直接通过"); + return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath); + } + if (xssProperties.getAuthUrls().size() > 0) { + for (String aurl : xssProperties.getAuthUrls()) { + if (url.contains(aurl)) { + log.info("免登陆url,免验签"); + return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath); + + } + } + } + String api_token = exchange.getRequest().getHeaders().getFirst(UserAuthContains.API_TOKEN); + String api_type = exchange.getRequest().getHeaders().getFirst(UserAuthContains.API_TYPE); + // String key = RedisConstans.IOT_TOKEN.concat(api_token); + // return reactiveRedisTemplate.getExpire(key).map(Duration::getSeconds).flatMap(ttl -> { + // if (ttl == -1) { + // // 用户没登陆 + // return Mono.error(new RuntimeException("未登录")); + // } else if (ttl <= 3600) { + // // token 将要失效 + // return reactiveRedisTemplate.expire(key, Duration.ofDays(7)).then(chain.filter(exchange)); + // } else { + // // 正常登录 + // return chain.filter(exchange); + // } + // }); + if (ObjectUtils.isEmpty(api_token) || ObjectUtils.isEmpty(api_type)) { + log.info("未传输token和type,需要登录"); + return Mono.error(new RuntimeException("未登录")); + } + return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath); + } + log.info("未开启xss验签认证"); + + return continueRequest(exchange, chain, realIpAddress, requestId, startTime,traceId,xForwardedPath); + } + + + private Mono continueRequest(ServerWebExchange exchange, WebFilterChain chain, String customerIp, String requestId, + long startTime,String traceId,String xForwardedPath){ + ServerWebExchange.Builder ex = exchange.mutate(); + ex.response(getResponse(exchange, requestId,traceId)); + ex.request(getRequest(exchange, customerIp, requestId,traceId,xForwardedPath)); + + return chain.filter(ex.build()).contextWrite(context -> { + Context contextTmp = context.put(Log4Constans.TRACE_ID, traceId); + return contextTmp; + }).doFinally(single ->{ + long endTime = System.currentTimeMillis(); + log.info("api end time:{}, total time:{}", endTime, endTime - startTime); + MDC.remove(LogMdcConfiguration.PRINT_LOG_ID); + }); + } + + private ServerHttpResponse getResponse(ServerWebExchange exchange, String requestId,String traceId){ + ServerHttpResponse response = exchange.getResponse(); + return new ServerHttpResponseDecorator(response){ + @Override + public Mono writeWith(Publisher body){ + MDC.put(Log4Constans.TRACE_ID, traceId); + if (body instanceof Flux) { + Flux fluxBody = Flux.from(body); + return super.writeWith(fluxBody.buffer().map(dataBuffers -> { + MDC.put(Log4Constans.TRACE_ID, traceId); + DataBufferFactory dataBufferFactory = new DefaultDataBufferFactory(); + DataBuffer joinBuffer = dataBufferFactory.join(dataBuffers); + byte[] returnContent = new byte[joinBuffer.readableByteCount()]; + joinBuffer.read(returnContent); + DataBufferUtils.release(joinBuffer); + String returnStr = new String(returnContent, StandardCharsets.UTF_8); + log.info("response:{}", returnStr); + return response.bufferFactory().wrap(returnContent); + })); + }else if(body instanceof Mono){ + Mono monoBody = Mono.from(body); + return super.writeWith(monoBody.map(dataBuffer -> { + MDC.put(Log4Constans.TRACE_ID, traceId); + log.info("response:{}", dataBuffer.toString(StandardCharsets.UTF_8)); + return response.bufferFactory().wrap(dataBuffer.toString(StandardCharsets.UTF_8).getBytes()); + })); + } + return super.writeWith(body); + } + }; + } + + + private ServerHttpRequest getRequest(ServerWebExchange exchange, String customerIp, String requestId, String traceId, String xForwardedPath) { + ServerHttpRequest request = exchange.getRequest(); + if (StringUtils.isNotEmpty(xForwardedPath)) { + String originXForwardedPath = xForwardedPath; + if (xForwardedPath.contains(ApiConstants.API_USER)) { + xForwardedPath = "/" + ApiConstants.API_USER + xForwardedPath.split(ApiConstants.API_USER)[1]; + } + log.info("getRequest xForwardedPath is not null originXForwardedPath:{},xForwardedPath:{}",originXForwardedPath, xForwardedPath); + request = request.mutate().path(xForwardedPath).build(); + } + + ServerHttpRequest newRequest = new ServerHttpRequestDecorator(request) { + /*@Override + public Flux getBody() { + Flux body = this.getDelegate().getBody(); + return body.map(dataBuffer -> { + log.info("request:{}", dataBuffer.toString(StandardCharsets.UTF_8)); + return dataBuffer; + }); + }*/ + @Override + public HttpHeaders getHeaders() { + HttpHeaders httpHeaders = new HttpHeaders(); + httpHeaders.putAll(super.getHeaders()); + httpHeaders.set(HEADER_X_FORWARDED_FOR, customerIp); + httpHeaders.set(Log4Constans.IP, customerIp); + httpHeaders.set(Log4Constans.TRACE_ID, traceId); + return httpHeaders; + } + }; + return newRequest; + } + /** + * 获取真实客户端IP + * @param serverHttpRequest + * @return + */ + public static String getRealIpAddress(ServerHttpRequest serverHttpRequest) { + String ipAddress; + try { + // 1.根据常见的代理服务器转发的请求ip存放协议,从请求头获取原始请求ip。 + ipAddress = serverHttpRequest.getHeaders().getFirst(HEADER_X_FORWARDED_FOR); + if (StringUtils.isEmpty(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) { + ipAddress = serverHttpRequest.getHeaders().getFirst(HEADER_PROXY_CLIENT_IP); + } + if (StringUtils.isEmpty(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) { + ipAddress = serverHttpRequest.getHeaders().getFirst(HEADER_WL_PROXY_CLIENT_IP); + } + + // 2.如果没有转发的ip,则取当前通信的请求端的ip + if (StringUtils.isEmpty(ipAddress) || UNKNOWN.equalsIgnoreCase(ipAddress)) { + InetSocketAddress inetSocketAddress = serverHttpRequest.getRemoteAddress(); + if(inetSocketAddress != null) { + ipAddress = inetSocketAddress.getAddress().getHostAddress(); + } + } + + // 对于通过多个代理的情况,第一个IP为客户端真实IP,多个IP按照','分割 + // "***.***.***.***" + if (ipAddress != null) { + ipAddress = ipAddress.split(SEPARATOR)[0].trim(); + } + } catch (Exception e) { + log.error("解析请求IP失败", e); + ipAddress = "解析IP失败"; + } + return ipAddress == null ? "解析IP失败" : ipAddress; + } + + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/filter/GlobalCacheRequestFilter.java b/api-gateway/src/main/java/com/heyu/api/gateway/filter/GlobalCacheRequestFilter.java new file mode 100644 index 0000000..30a2282 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/filter/GlobalCacheRequestFilter.java @@ -0,0 +1,39 @@ +package com.heyu.api.gateway.filter; + +import org.springframework.cloud.gateway.filter.GatewayFilterChain; +import org.springframework.cloud.gateway.filter.GlobalFilter; +import org.springframework.cloud.gateway.support.ServerWebExchangeUtils; +import org.springframework.core.Ordered; +import org.springframework.stereotype.Component; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * 全局缓存获取body请求数据(解决流不能重复读取问题). + * + * @author yangning + * @since 2022/12/14 16:07 + */ +@Component +public class GlobalCacheRequestFilter implements GlobalFilter, Ordered { + + @Override + public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) { + // 只缓存json类型请求 + // if (!WebFluxUtils.isJsonRequest(exchange)) { + // return chain.filter(exchange); + // } + return ServerWebExchangeUtils.cacheRequestBody(exchange, (serverHttpRequest) -> { + if (serverHttpRequest == exchange.getRequest()) { + return chain.filter(exchange); + } + return chain.filter(exchange.mutate().request(serverHttpRequest).build()); + }); + } + + @Override + public int getOrder() { + return Ordered.HIGHEST_PRECEDENCE; + } + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/filter/LogMdcConfiguration.java b/api-gateway/src/main/java/com/heyu/api/gateway/filter/LogMdcConfiguration.java new file mode 100644 index 0000000..1df5779 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/filter/LogMdcConfiguration.java @@ -0,0 +1,82 @@ +package com.heyu.api.gateway.filter; + +import com.heyu.api.gateway.util.Log4Constans; +import lombok.extern.slf4j.Slf4j; +import org.reactivestreams.Subscription; +import org.slf4j.MDC; +import org.springframework.context.annotation.Configuration; +import reactor.core.CoreSubscriber; +import reactor.core.publisher.Hooks; +import reactor.core.publisher.Operators; +import reactor.util.context.Context; + +import javax.annotation.PostConstruct; +import javax.annotation.PreDestroy; + +/** + *

+ *

*日志上下文切换配置 + * @author wulin + * @since 2023-08-07 + */ +@Configuration +@Slf4j +public class LogMdcConfiguration { + public static String PRINT_LOG_ID = Log4Constans.TRACE_ID; + private int errHashcode; + @PostConstruct + public void contextOperatorHook() { + Hooks.onEachOperator(PRINT_LOG_ID, Operators.lift((r, c) ->{ + return new MdcContextSubscriber(c); + })); + } + @PreDestroy + public void cleanupHook() { + Hooks.resetOnEachOperator(PRINT_LOG_ID); + } + + class MdcContextSubscriber implements CoreSubscriber { + private CoreSubscriber coreSubscriber; + public MdcContextSubscriber(CoreSubscriber c){ + coreSubscriber = c; + } + + @Override + public void onComplete() { + coreSubscriber.onComplete(); + //暂时去掉,让每次切换时更换,即onNext插入 + //MDC.remove(PRINT_LOG_ID); + } + + @Override + public void onError(Throwable throwable) { + + if(errHashcode != throwable.hashCode()){ + errHashcode = throwable.hashCode(); + log.info("异常{}", throwable); + } + coreSubscriber.onError(throwable); + MDC.remove(PRINT_LOG_ID); + + } + + @Override + public void onSubscribe(Subscription subscription) { + coreSubscriber.onSubscribe(subscription); + } + + @Override + public void onNext(T t) { + if(coreSubscriber.currentContext().hasKey(PRINT_LOG_ID)){ + MDC.put(PRINT_LOG_ID, coreSubscriber.currentContext().get(PRINT_LOG_ID)); + } + coreSubscriber.onNext(t); + } + + + @Override + public Context currentContext() { + return coreSubscriber.currentContext(); + } + } +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/handler/GatewayExceptionHandler.java b/api-gateway/src/main/java/com/heyu/api/gateway/handler/GatewayExceptionHandler.java new file mode 100644 index 0000000..df34c94 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/handler/GatewayExceptionHandler.java @@ -0,0 +1,49 @@ +package com.heyu.api.gateway.handler; + +import com.heyu.api.gateway.util.WebFluxUtils; +import lombok.extern.slf4j.Slf4j; +import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler; +import org.springframework.cloud.gateway.support.NotFoundException; +import org.springframework.context.annotation.Configuration; +import org.springframework.core.annotation.Order; +import org.springframework.http.server.reactive.ServerHttpResponse; +import org.springframework.web.server.ResponseStatusException; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * 网关统一异常处理. + * + */ +@Slf4j +@Order(-1) +@Configuration +public class GatewayExceptionHandler implements ErrorWebExceptionHandler { + + @Override + public Mono handle(ServerWebExchange exchange, Throwable ex) { + final ServerHttpResponse response = exchange.getResponse(); + + if (exchange.getResponse().isCommitted()) { + return Mono.error(ex); + } + + String msg; + + if (ex instanceof NotFoundException) { + msg = "服务未找到"; + } else if (ex instanceof ResponseStatusException) { + ResponseStatusException responseStatusException = (ResponseStatusException) ex; + msg = responseStatusException.getMessage(); + } else if (ex instanceof RuntimeException) { + msg = ex.getMessage(); + } else { + msg = "内部服务器错误"; + } + + log.error("[网关异常处理]请求路径:{},异常信息:{}", exchange.getRequest().getPath(), ex.getMessage()); + + return WebFluxUtils.webFluxResponseWriter(response, msg); + } + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/ApiConstants.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/ApiConstants.java new file mode 100644 index 0000000..a1a7ba8 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/ApiConstants.java @@ -0,0 +1,92 @@ +package com.heyu.api.gateway.util; + +public class ApiConstants { + public static final Integer Int_0 = new Integer(0); + public static final Integer Int_1 = new Integer(1); + public static final Integer Int_2 = new Integer(2); + public static final Integer Int_3 = new Integer(3); + + /** + * 不需要 注解名称 + */ + public static final String NOT_INTERCEPT_ANNOTATION_NAME = "NotIntercept"; + /** + * token相关的所有信息 + */ + public static final String TOKEN_INFO = "TOKEN_INFO$"; + + /** + * account 信息 + */ + public static final String ACCOUNT_INFO = "ACCOUNT_INFO$"; + + /** + * token 一分钟访问次数 + */ + public static final String TOKEN_MINUTES_VISIT_COUNT = "TOKEN_MINUTES_VISIT_COUNT$"; + + /** + * account账号一分钟访问次数 + */ + public static final String ACCOUNT_MINUTES_VISIT_COUNT = "ACCOUNT_MINUTES_VISIT_COUNT$"; + + /** + * update account amount lock + */ + public static final String UPDATE_ACCOUNT_AMOUNT_LOCK = "UPDATE_ACCOUNT_AMOUNT_LOCK$"; + + + public static String SYSTEM = "system"; + + public static String USER_NAME = "user_name"; + + public static String TOKEN = "token"; + + + + /** + * 任务调度参数key + */ + public static final String JOB_PARAM_KEY = "JOB_PARAM_KEY"; + + + /** + * 定时任务状态 + * + * @author chenshun + * @email sunlightcs@gmail.com + * @date 2016年12月3日 上午12:07:22 + */ + public enum ScheduleStatus { + /** + * 正常 + */ + NORMAL(0), + /** + * 暂停 + */ + PAUSE(1); + + private int value; + + ScheduleStatus(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + } + + + + + public static final String VERIFY_INTERFACE = "verifyInterface"; + + public static final String ECHOBACK = "echoback"; + public static final String X_FORWARDED_PATH = "X-Forwarded-Path"; + + public static final String API_USER = "api-user"; + + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/Log4Constans.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/Log4Constans.java new file mode 100644 index 0000000..152f26e --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/Log4Constans.java @@ -0,0 +1,25 @@ +package com.heyu.api.gateway.util; + +public class Log4Constans { + + /** + * traceId ,日志编号 + */ + public static String TRACE_ID = "logid"; + + /** + * ip 值 + */ + public static String IP = "request_ip"; + + + /** + * 请求uri + */ + public static String URI = "request_uri"; + + /** + * 耗时 + */ + public static String START_TIME = "start_time"; +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/OrderUtils.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/OrderUtils.java new file mode 100644 index 0000000..1c9dcbb --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/OrderUtils.java @@ -0,0 +1,34 @@ +package com.heyu.api.gateway.util; + +import lombok.extern.slf4j.Slf4j; + +import java.text.SimpleDateFormat; + + +/** + * 订单号生成工具 + * 枚举相关信息,查看 https://www.showdoc.cc/web/#/page/495445295769339 + */ +@Slf4j +public class OrderUtils { + + public static String getUserPoolOrder() { + SimpleDateFormat dateformat = new SimpleDateFormat("SSSyyyyMMddHHmmss"); + StringBuffer sb = new StringBuffer(); + return sb. + append((int) (Math.random() * 1000)).append(dateformat.format(System.currentTimeMillis())).toString(); + } + + + + + public static String getOrderNo(String pre) { + SimpleDateFormat dateformat = new SimpleDateFormat("yyyyMMddHHmmssSSS"); + StringBuffer sb = new StringBuffer(pre); + return sb. + append((int) (Math.random() * 1000)).append(dateformat.format(System.currentTimeMillis())).toString(); + } + + + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/UserAuthContains.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/UserAuthContains.java new file mode 100644 index 0000000..5778fa6 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/UserAuthContains.java @@ -0,0 +1,16 @@ +package com.heyu.api.gateway.util; + +/** + * XXX + * + * @author weiyachao 包含 + * @since 2023/9/20 16:25 + */ +public interface UserAuthContains { + + String API_TOKEN = "Api-Token"; + + String API_TYPE = "Api-Type"; + + +} diff --git a/api-gateway/src/main/java/com/heyu/api/gateway/util/WebFluxUtils.java b/api-gateway/src/main/java/com/heyu/api/gateway/util/WebFluxUtils.java new file mode 100644 index 0000000..f7bd299 --- /dev/null +++ b/api-gateway/src/main/java/com/heyu/api/gateway/util/WebFluxUtils.java @@ -0,0 +1,88 @@ +package com.heyu.api.gateway.util; + +import com.alibaba.fastjson.JSON; +import java.util.HashMap; +import org.springframework.core.io.buffer.DataBuffer; +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.util.StringUtils; +import org.springframework.web.server.ServerWebExchange; +import reactor.core.publisher.Mono; + +/** + * WebFlux 工具类. + */ +public class WebFluxUtils { + + /** + * 是否是Json请求. + * + * @param exchange HTTP请求 + */ + public static boolean isJsonRequest(ServerWebExchange exchange) { + String header = exchange.getRequest().getHeaders().getFirst(HttpHeaders.CONTENT_TYPE); + return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE); + } + + /** + * 设置webflux模型响应. + * + * @param response ServerHttpResponse + * @param value 响应内容 + * @return Mono + */ + public static Mono webFluxResponseWriter(ServerHttpResponse response, Object value) { + return webFluxResponseWriter(response, HttpStatus.OK, value, HttpStatus.INTERNAL_SERVER_ERROR.value()); + } + + /** + * 设置webflux模型响应. + * + * @param response ServerHttpResponse + * @param code 响应状态码 + * @param value 响应内容 + * @return Mono + */ + public static Mono webFluxResponseWriter(ServerHttpResponse response, Object value, int code) { + return webFluxResponseWriter(response, HttpStatus.OK, value, code); + } + + /** + * 设置webflux模型响应. + * + * @param response ServerHttpResponse + * @param status http状态码 + * @param code 响应状态码 + * @param value 响应内容 + * @return Mono + */ + public static Mono webFluxResponseWriter(ServerHttpResponse response, HttpStatus status, Object value, + int code) { + return webFluxResponseWriter(response, MediaType.APPLICATION_JSON_VALUE, status, value, code); + } + + /** + * 设置webflux模型响应. + * + * @param response ServerHttpResponse + * @param contentType content-type + * @param status http状态码 + * @param code 响应状态码 + * @param value 响应内容 + * @return Mono + */ + public static Mono webFluxResponseWriter(ServerHttpResponse response, String contentType, HttpStatus status, + Object value, int code) { + response.setStatusCode(status); + response.getHeaders().add(HttpHeaders.CONTENT_TYPE, contentType); + HashMap map = new HashMap<>(); + map.put("message", value.toString()); + map.put("status", code); + map.put("code", "500"); + map.put("timestamp", System.currentTimeMillis()); + DataBuffer dataBuffer = response.bufferFactory().wrap(JSON.toJSONString(map).getBytes()); + return response.writeWith(Mono.just(dataBuffer)); + } +} diff --git a/api-gateway/src/main/resources/bootstrap-dev.yml b/api-gateway/src/main/resources/bootstrap-dev.yml new file mode 100644 index 0000000..539ce7c --- /dev/null +++ b/api-gateway/src/main/resources/bootstrap-dev.yml @@ -0,0 +1,84 @@ +spring: + cloud: + inetutils: + preferredNetworks: + - 192.168 #注册到nacos中心优先匹配的IP + gateway: + routes: + - id: heyu-api-user-api + uri: lb://heyu-api-user-api + predicates: + - Path=/api-user/** + filters: + # 转发时去掉一层路径 + - StripPrefix=1 + - id: heyu-api-websocket + uri: lb://heyu-api-websocket + predicates: + - Path=/api-websocket/** + filters: + # 转发时去掉一层路径 + - StripPrefix=1 + globalcors: + corsConfigurations: + '[/**]': + # 允许携带认证信息 + allow-credentials: true + # 允许跨域的源(网站域名/ip),设置*为全部 + allowedOriginPatterns: "*" + # 允许跨域的method, 默认为GET和OPTIONS,设置*为全部 + allowedMethods: "*" + # 允许跨域请求里的head字段,设置*为全部 + allowedHeaders: "*" + config: + # 如果本地配置优先级高,那么 override-none 设置为 true,包括系统环境变量、本地配置文件等配置 + override-none: true + # 如果想要远程配置优先级高,那么 allow-override 设置为 false,如果想要本地配置优先级高那么 allow-override 设置为 true + allow-override: true + # 只有系统环境变量或者系统属性才能覆盖远程配置文件的配置,本地配置文件中配置优先级低于远程配置;注意本地配置文件不是系统属性 + override-system-properties: false + nacos: + discovery: + # 服务注册地址 + server-addr: nacos.iwulin.tech:30571 + namespace: ${spring.profiles.active} + password: hz_HeYu@202518 + config: + namespace: ${spring.profiles.active} + # 配置中心地址 + server-addr: nacos.iwulin.tech:30571 + password: hz_HeYu@202518 + # 配置文件格式 + file-extension: yml + # 共享配置 + #shared-configs: + # - application-${spring.profiles.active}.${spring.cloud.nacos.config.file-extension} + redis: + password: O^pv_3#slxQ + port: 32048 + host: rrdd.iwulin.tech + timeout: 5000 +# 安全配置 +security: + # 防止XSS攻击 + xss: + enabled: false + # 排除的路径 + exclude-urls: + - /api-user/user/login/pwd + - /api-user/ip/api/getIp + - /api-websocket/push/message + - /api-websocket/websocket/box + - /api-websocket/websocket/customer + - /api-websocket/websocket/tts/token + - /api-websocket/websocket/init/sysTalkAnswer + # ip免登白名单 + auth-ip: #127.0.0.1,192.168.8.141 + #免登,免校验url + auth-urls: + - /actuator + - /websocket +#application: +# cors: +# allowed-crigin-patterns: +# - /api-user/user/user/login/pwd diff --git a/api-gateway/src/main/resources/bootstrap-online.yml b/api-gateway/src/main/resources/bootstrap-online.yml new file mode 100644 index 0000000..c508d58 --- /dev/null +++ b/api-gateway/src/main/resources/bootstrap-online.yml @@ -0,0 +1,18 @@ +spring: + cloud: + nacos: + discovery: + # 服务注册地址 + server-addr: 127.0.0.1:8848 + namespace: ${spring.profiles.active} + #password: hz_HeYu@202518 + config: + # 配置中心地址 + server-addr: 127.0.0.1:8848 + namespace: ${spring.profiles.active} + #password: hz_HeYu@202518 + # 配置文件格式 + file-extension: yml + # 共享配置 + #shared-configs: + # - application.${spring.cloud.nacos.config.file-extension} diff --git a/api-gateway/src/main/resources/bootstrap.yml b/api-gateway/src/main/resources/bootstrap.yml new file mode 100644 index 0000000..8c6b851 --- /dev/null +++ b/api-gateway/src/main/resources/bootstrap.yml @@ -0,0 +1,32 @@ +server: + port: 8080 +spring: + application: + name: heyu-api-gateway + profiles: + active: dev + main: + allow-bean-definition-overriding: true + allow-circular-references: true + + + +zuul: + ribbon: + eager-load: + enabled: true + clients: heyu-api-user-api + ignoredServices: '*' + host: + connect-timeout-millis: 10000 + socket-timeout-millis: 10000 + ratelimit: + key-prefix: pig-ratelimite + enabled: true + repository: REDIS + behind-proxy: true + policies: + sina-upms-service: + limit: 100 + quota: 100 + refresh-interval: 3 diff --git a/api-gateway/src/main/resources/logback-dev.xml b/api-gateway/src/main/resources/logback-dev.xml new file mode 100644 index 0000000..1281941 --- /dev/null +++ b/api-gateway/src/main/resources/logback-dev.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + ${log.pattern} + UTF-8 + + + + + + ${log.path}/all.log + + + + ${log.path}/%d{yyyy-MM-dd}_all.log + + 15 + + + ${log.pattern} + UTF-8 + + + + INFO + + + + + + + ${log.path}/warn.log + + + + ${log.path}/%d{yyyy-MM-dd}_wran.log + + 15 + + + ${log.pattern} + UTF-8 + + + + WARN + + + + + ${log.path}/error.log + + + + ${log.path}/%d{yyyy-MM-dd}_error.log + + 15 + + + ${log.pattern} + UTF-8 + + + + ERROR + + + + + + + + + + + + \ No newline at end of file diff --git a/api-gateway/src/main/resources/logback-prod.xml b/api-gateway/src/main/resources/logback-prod.xml new file mode 100644 index 0000000..6f6fde7 --- /dev/null +++ b/api-gateway/src/main/resources/logback-prod.xml @@ -0,0 +1,85 @@ + + + + + + + + + + + + ${log.pattern} + UTF-8 + + + + + + ${log.path}/all.log + + + + ${log.path}/%d{yyyy-MM-dd}_all.log + + 15 + + + ${log.pattern} + UTF-8 + + + + INFO + + + + + + + ${log.path}/warn.log + + + + ${log.path}/%d{yyyy-MM-dd}_wran.log + + 15 + + + ${log.pattern} + UTF-8 + + + + WARN + + + + + ${log.path}/error.log + + + + ${log.path}/%d{yyyy-MM-dd}_error.log + + 15 + + + ${log.pattern} + UTF-8 + + + + ERROR + + + + + + + + + + + + \ No newline at end of file diff --git a/api-gateway/src/main/resources/logback-test.xml b/api-gateway/src/main/resources/logback-test.xml new file mode 100644 index 0000000..09ffc80 --- /dev/null +++ b/api-gateway/src/main/resources/logback-test.xml @@ -0,0 +1,84 @@ + + + + + + + + + + + ${log.pattern} + UTF-8 + + + + + + ${log.path}/all.log + + + + ${log.path}/%d{yyyy-MM-dd}_all.log + + 15 + + + ${log.pattern} + UTF-8 + + + + INFO + + + + + + + ${log.path}/warn.log + + + + ${log.path}/%d{yyyy-MM-dd}_wran.log + + 15 + + + ${log.pattern} + UTF-8 + + + + WARN + + + + + ${log.path}/error.log + + + + ${log.path}/%d{yyyy-MM-dd}_error.log + + 15 + + + ${log.pattern} + UTF-8 + + + + ERROR + + + + + + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 8d49f46..242d2e6 100644 --- a/pom.xml +++ b/pom.xml @@ -21,6 +21,7 @@ api-mapper api-third api-web + api-gateway 0.0.1-SNAPSHOT 易借消息服务