1. 统一包名修改

This commit is contained in:
chenbowen
2025-09-22 02:03:22 +08:00
parent 516ca4aefd
commit a001fc8f16
2921 changed files with 16154 additions and 16154 deletions

View File

@@ -0,0 +1,14 @@
package com.zt.plat.gateway;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class GatewayServerApplication {
public static void main(String[] args) {
// 启动 Spring Boot 应用
SpringApplication.run(GatewayServerApplication.class, args);
}
}

View File

@@ -0,0 +1,48 @@
package com.zt.plat.gateway.filter.cors;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
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.cors.reactive.CorsUtils;
import org.springframework.web.server.ServerWebExchange;
import org.springframework.web.server.WebFilter;
import org.springframework.web.server.WebFilterChain;
import reactor.core.publisher.Mono;
/**
* 跨域 Filter
*
* @author ZT
*/
@Component
public class CorsFilter implements WebFilter {
private static final String ALL = "*";
private static final String MAX_AGE = "3600L";
@Override
public Mono<Void> filter(ServerWebExchange exchange, WebFilterChain chain) {
// 非跨域请求,直接放行
ServerHttpRequest request = exchange.getRequest();
if (!CorsUtils.isCorsRequest(request)) {
return chain.filter(exchange);
}
// 设置跨域响应头
ServerHttpResponse response = exchange.getResponse();
HttpHeaders headers = response.getHeaders();
headers.add("Access-Control-Allow-Origin", ALL);
headers.add("Access-Control-Allow-Methods", ALL);
headers.add("Access-Control-Allow-Headers", ALL);
headers.add("Access-Control-Max-Age", MAX_AGE);
if (request.getMethod() == HttpMethod.OPTIONS) {
response.setStatusCode(HttpStatus.OK);
return Mono.empty();
}
return chain.filter(exchange);
}
}

View File

@@ -0,0 +1,54 @@
package com.zt.plat.gateway.filter.cors;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.cloud.gateway.filter.NettyWriteResponseFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* 解决 Spring Cloud Gateway 2.x 跨域时,出现重复 Origin 的 BUG
*
* 参考文档:<a href="https://blog.csdn.net/zimou5581/article/details/90043178" />
*
* @author ZT
*/
@Component
public class CorsResponseHeaderFilter implements GlobalFilter, Ordered {
@Override
public int getOrder() {
// 指定此过滤器位于 NettyWriteResponseFilter 之后
// 即待处理完响应体后接着处理响应头
return NettyWriteResponseFilter.WRITE_RESPONSE_FILTER_ORDER + 1;
}
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return chain.filter(exchange).then(Mono.defer(() -> {
// https://gitee.com/zhijiantianya/cloud-cloud/pulls/177/
List<String> keysToModify = exchange.getResponse().getHeaders().entrySet().stream()
.filter(kv -> (kv.getValue() != null && kv.getValue().size() > 1))
.filter(kv -> (kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN)
|| kv.getKey().equals(HttpHeaders.ACCESS_CONTROL_ALLOW_CREDENTIALS)))
.map(Map.Entry::getKey)
.collect(Collectors.toList());
keysToModify.forEach(key->{
List<String> values = exchange.getResponse().getHeaders().get(key);
if (values != null && !values.isEmpty()) {
exchange.getResponse().getHeaders().put(key, Collections.singletonList(values.get(0)));
}
});
return chain.filter(exchange);
}));
}
}

View File

@@ -0,0 +1,92 @@
package com.zt.plat.gateway.filter.logging;
import lombok.Data;
import org.springframework.cloud.gateway.route.Route;
import org.springframework.http.HttpStatus;
import org.springframework.util.MultiValueMap;
import java.time.LocalDateTime;
/**
* 网关的访问日志
*/
@Data
public class AccessLog {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 路由
*
* 类似 ApiAccessLogCreateReqDTO 的 applicationName
*/
private Route route;
/**
* 协议
*/
private String schema;
/**
* 请求方法名
*/
private String requestMethod;
/**
* 访问地址
*/
private String requestUrl;
/**
* 查询参数
*/
private MultiValueMap<String, String> queryParams;
/**
* 请求体
*/
private String requestBody;
/**
* 请求头
*/
private MultiValueMap<String, String> requestHeaders;
/**
* 用户 IP
*/
private String userIp;
/**
* 响应体
*
* 类似 ApiAccessLogCreateReqDTO 的 resultCode + resultMsg
*/
private String responseBody;
/**
* 响应头
*/
private MultiValueMap<String, String> responseHeaders;
/**
* 响应结果
*/
private HttpStatus httpStatus;
/**
* 开始请求时间
*/
private LocalDateTime startTime;
/**
* 结束请求时间
*/
private LocalDateTime endTime;
/**
* 执行时长,单位:毫秒
*/
private Integer duration;
}

View File

@@ -0,0 +1,44 @@
package com.zt.plat.gateway.filter.security;
import lombok.Data;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
/**
* 登录用户信息
*
* copy from cloud-spring-boot-starter-security 的 LoginUser 类
*
* @author ZT
*/
@Data
public class LoginUser {
/**
* 用户编号
*/
private Long id;
/**
* 用户类型
*/
private Integer userType;
/**
* 额外的用户信息
*/
private Map<String, String> info;
/**
* 租户编号
*/
private Long tenantId;
/**
* 授权范围
*/
private List<String> scopes;
/**
* 过期时间
*/
private LocalDateTime expiresTime;
}

View File

@@ -0,0 +1,74 @@
package com.zt.plat.gateway.handler;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.gateway.util.WebFrameworkUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.reactive.error.ErrorWebExceptionHandler;
import org.springframework.core.annotation.Order;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;
import static com.zt.plat.framework.common.exception.enums.GlobalErrorCodeConstants.INTERNAL_SERVER_ERROR;
/**
* Gateway 的全局异常处理器,将 Exception 翻译成 CommonResult + 对应的异常编号
*
* 在功能上,和 cloud-spring-boot-starter-web 的 GlobalExceptionHandler 类是一致的
*
* @author ZT
*/
@Component
@Order(-1) // 保证优先级高于默认的 Spring Cloud Gateway 的 ErrorWebExceptionHandler 实现
@Slf4j
public class GlobalExceptionHandler implements ErrorWebExceptionHandler {
@Override
public Mono<Void> handle(ServerWebExchange exchange, Throwable ex) {
// 已经 commit则直接返回异常
ServerHttpResponse response = exchange.getResponse();
if (response.isCommitted()) {
return Mono.error(ex);
}
// 转换成 CommonResult
CommonResult<?> result;
if (ex instanceof ResponseStatusException) {
result = responseStatusExceptionHandler(exchange, (ResponseStatusException) ex);
} else {
result = defaultExceptionHandler(exchange, ex);
}
// 返回给前端
return WebFrameworkUtils.writeJSON(exchange, result);
}
/**
* 处理 Spring Cloud Gateway 默认抛出的 ResponseStatusException 异常
*/
private CommonResult<?> responseStatusExceptionHandler(ServerWebExchange exchange,
ResponseStatusException ex) {
// TODO 芋艿:这里要精细化翻译,默认返回用户是看不懂的
ServerHttpRequest request = exchange.getRequest();
log.error("[responseStatusExceptionHandler][uri({}/{}) 发生异常]", request.getURI(), request.getMethod(), ex);
return CommonResult.error(ex.getStatusCode().value(), ex.getReason());
}
/**
* 处理系统异常,兜底处理所有的一切
*/
@ExceptionHandler(value = Exception.class)
public CommonResult<?> defaultExceptionHandler(ServerWebExchange exchange,
Throwable ex) {
ServerHttpRequest request = exchange.getRequest();
log.error("[defaultExceptionHandler][uri({}/{}) 发生异常]", request.getURI(), request.getMethod(), ex);
// TODO 芋艿:是否要插入异常日志呢?
// 返回 ERROR CommonResult
return CommonResult.error(INTERNAL_SERVER_ERROR.getCode(), INTERNAL_SERVER_ERROR.getMsg());
}
}

Some files were not shown because too many files have changed in this diff Show More