merge project

This commit is contained in:
白茶清欢 2025-06-06 21:23:59 +08:00
parent ff2e558a0c
commit 688eb26c1e
10 changed files with 394 additions and 7 deletions

41
pom.xml
View File

@ -5,8 +5,8 @@
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<groupId>cn.zhangdeman</groupId> <groupId>cn.zhangdeman</groupId>
<artifactId>exception</artifactId> <artifactId>springboot-common</artifactId>
<version>1.0-SNAPSHOT</version> <version>0.0.1-SNAPSHOT</version>
<properties> <properties>
<maven.compiler.source>21</maven.compiler.source> <maven.compiler.source>21</maven.compiler.source>
@ -19,11 +19,6 @@
<artifactId>spring-context</artifactId> <artifactId>spring-context</artifactId>
<version>6.1.14</version> <version>6.1.14</version>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.30</version>
</dependency>
<dependency> <dependency>
<groupId>jakarta.servlet</groupId> <groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId> <artifactId>jakarta.servlet-api</artifactId>
@ -36,6 +31,38 @@
<version>4.13.2</version> <version>4.13.2</version>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.38</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>2.0.17</version>
</dependency>
<!-- jackson 2.x 相关依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.19.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>3.4.7-SNAPSHOT</version>
</dependency>
</dependencies> </dependencies>
<repositories> <repositories>

View File

@ -0,0 +1,9 @@
package cn.zhangdeman.filter;
// http 一些枚举key
public class HttpField {
private static final String HEADER_TRACE_ID = "X-Front-Trace-Id"; // 透传过来的trace id
private static final String HEADER_CLIENT_IP = "X-Client-Ip"; // 请求来源IP
private static final String HEADER_USER_AGENT = "User-Agent"; // 请求来源 ua
private static final String HEADER_AUTHORIZATION = "Authorization"; // 请求来源 authorization
}

View File

@ -0,0 +1,22 @@
package cn.zhangdeman.filter;
// 日志相关数据的枚举值
public class LogField {
// 定义日志类型
public static final String LOG_TYPE_ACCESS = "access"; // 服务请求记录
public static final String LOG_TYPE_INPUT = "input"; // 请求输入信息
public static final String LOG_TYPE_OUTPUT = "output"; // 请求输出信息
public static final String LOG_TYPE_API = "api"; // 接口请求记录
public static final String LOG_TYPE_MONITOR = "monitor"; // 系统监控
public static final String LOG_TYPE_DATABASE = "database"; // 数据库
public static final String LOG_TYPE_REDIS = "redis"; // redis日志
public static final String LOG_TYPE_KAFKA = "kafka"; // kafka日志
// 定义各种日志文件名称
public static final String LOG_ACCESS_NAME = "access.log"; // 访问日志
public static final String LOG_REQUEST_NAME = "request.log"; // 请求日志
public static final String LOG_API_NAME = "api.log"; // 三方调用日志
public static final String LOG_MONITOR_NAME = "monitor.log"; // 监控日志
public static final String LOG_DATABASE_NAME = "database.log"; // 数据库日志
public static final String LOG_CACHE_NAME = "cache.log"; // 缓存日志
public static final String LOG_MESSAGE_NAME = "message.log"; // 消息队列日志
}

View File

@ -0,0 +1,7 @@
package cn.zhangdeman.filter;
public class Main {
public static void main(String[] args) {
}
}

View File

@ -0,0 +1,5 @@
package cn.zhangdeman.filter;
public class Ordered {
public static final int REQUEST_ID = -10000; // 请求ID生成过滤器
}

View File

@ -0,0 +1,37 @@
package cn.zhangdeman.filter;
// 记录的各种字段枚举值
public class RecordField {
public static final String TRACE_ID = "trace_id"; // trace_id
public static final String REQUEST_ID = "request_id"; // request_id
public static final String START_TIMESTAMP = "start_timestamp"; // 开始请求时间
public static final String FINISH_TIMESTAMP = "finish_timestamp"; // 完成请求时间
public static final String SERVER_IP = "server_ip"; // 服务器IP
public static final String SERVER_HOSTNAME = "server_hostname"; // 服务器名称
public static final String COST = "cost"; // 请求耗时
public static final String CONTEXT_DATA = "context_data"; // 本条日志的上下文信息
// 请求信息
public static final String REQUEST_INFO = "request_info"; // 请求信息
public static final String REQUEST_UA = "user_agent"; // 请求ua
public static final String REQUEST_CLIENT_IP = "client_ip"; // 请求客户端
public static final String REQUEST_METHOD = "method"; // 请求方法
public static final String REQUEST_CONTENT_TYPE = "content_type"; // 请求类型
public static final String REQUEST_QUERY = "_query"; // query参数
public static final String REQUEST_BODY = "body"; // body参数
public static final String REQUEST_HEADER = "header"; // header参数
public static final String REQUEST_COOKIE = "cookie"; // cookie参数
public static final String REQUEST_PATH_PARAM = "path_param"; // path参数
public static final String REQUEST_SIZE = "size"; // 参数大小
public static final String REQUEST_URI = "uri"; // 请求接口
public static final String RUNTIME_THREAD_CONTEXT = "runtime_thread_context"; // 运行时线程上下文
public static final String RESPONSE_INFO = "response_data"; // 接口响应数据
public static final String RESPONSE_CODE = "code"; // 接口响应数据状态码
public static final String RESPONSE_MESSAGE = "message"; // 接口响应数据状态码描述
public static final String RESPONSE_DATA = "data"; // 接口响应数据
public static final String RESPONSE_ERROR_DETAIL = "err_detail"; // 异常详细信息
public static final String RESPONSE_HTTP_CODE = "http_code"; // 苍蝇状态码,默认200
public static final String RESPONSE_HEADER = "header"; // 响应header
public static final String RESPONSE_COOKIE = "cookie"; // 响应header
}

View File

@ -0,0 +1,41 @@
package cn.zhangdeman.filter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.servlet.http.HttpServletRequest;
import lombok.Getter;
import lombok.Setter;
import java.util.Map;
// 请求相关数据
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true) // 忽略未知属性字段
public class Request {
@JsonIgnore
HttpServletRequest httpServletRequest;// 原始请求
@JsonProperty(RecordField.REQUEST_UA)
private String userAgent; // 客户端ua
@JsonProperty(RecordField.REQUEST_CLIENT_IP)
private String clientIp; // 客户端IP
@JsonProperty(RecordField.REQUEST_METHOD)
private String requestMethod; // 请求方法
@JsonProperty(RecordField.REQUEST_CONTENT_TYPE)
private String requestContentType; // 请求类型
@JsonProperty(RecordField.REQUEST_QUERY)
private Map<String, String> requestQuery; // 请求query
@JsonProperty(RecordField.REQUEST_HEADER)
private Map<String, String> requestHeader; // 请求header
@JsonProperty(RecordField.REQUEST_COOKIE)
private Map<String, String> requestCookie; // 请求cookie
@JsonProperty(RecordField.REQUEST_PATH_PARAM)
private Map<String, String> requestPathParam; // path 参数
@JsonProperty(RecordField.REQUEST_BODY)
private String requestBody; // 请求body
@JsonIgnore
private byte[] requestBodyRaw; // 原始请求body
@JsonProperty(RecordField.REQUEST_URI)
private String requestUri; // 请求接口
}

View File

@ -0,0 +1,48 @@
package cn.zhangdeman.filter;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Getter;
import lombok.Setter;
import java.util.HashMap;
import java.util.Map;
// 响应数据
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true) // 忽略未知属性字段
public class Response {
@JsonProperty(RecordField.RESPONSE_CODE)
private String code; // 响应业务状态码
@JsonProperty(RecordField.RESPONSE_MESSAGE)
private String message; // 响应消息
@JsonProperty(RecordField.RESPONSE_DATA)
private Object data; // 响应数据
@JsonProperty(RecordField.RESPONSE_ERROR_DETAIL)
private Object errorDetail; // 异常详情
@JsonProperty(RecordField.RESPONSE_HTTP_CODE)
private Integer httpCode = 200; // 响应http状态码
@JsonProperty(RecordField.RESPONSE_HEADER)
private Map<String, String> header; // 响应头
@JsonProperty(RecordField.RESPONSE_COOKIE)
private Map<String, String> cookie; // 响应cookie
@JsonIgnore
private HttpServletResponse httpServletResponse; // 响应实例
public void addHeader(String key, String value) {
if (null == this.header) {
this.header = new HashMap<>();
}
this.header.put(key, value);
}
public void addCookie(String key, String value) {
if (null == this.cookie) {
this.cookie = new HashMap<>();
}
this.cookie.put(key, value);
}
}

View File

@ -0,0 +1,62 @@
package cn.zhangdeman.filter;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.Getter;
import lombok.Setter;
import java.io.Serializable;
import java.util.Map;
// 初始化的请求信息
@Getter
@Setter
@JsonIgnoreProperties(ignoreUnknown = true) // 忽略未知属性字段
public class RuntimeContext implements Serializable {
@JsonProperty(RecordField.REQUEST_ID)
private String requestId; // 本次请求request id
@JsonProperty(RecordField.COST)
private Long cost; // 请求耗时
@JsonProperty(RecordField.SERVER_IP)
private String serverIp; // 服务器Ip
@JsonProperty(RecordField.SERVER_HOSTNAME)
private String serverHostname; // 服务器hostname
@JsonProperty(RecordField.FINISH_TIMESTAMP)
private Long finishTimeStamp; // 完成请求时间
@JsonProperty(RecordField.TRACE_ID)
private String traceId; // 全局trace id
@JsonProperty(RecordField.START_TIMESTAMP)
private Long startTimeStamp; // 开始请求时间
@JsonProperty(RecordField.CONTEXT_DATA)
private Map<String, Object> logData; // 本条日志的上下文信息
@JsonProperty(RecordField.REQUEST_INFO)
private Request requestInfo;// 请求信息
@JsonProperty(RecordField.RESPONSE_INFO)
private Response responseInfo; // 响应信息
// 序列化
@Override
public String toString() {
ObjectMapper mapper = new ObjectMapper();
try {
return mapper.writeValueAsString(this);
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
}
}
// 序列化
public String serializable() {
return toString();
}
// 反序列化
public RuntimeContext unserializable(String json) throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
return mapper.readValue(json, new TypeReference<RuntimeContext>() {
});
}
}

View File

@ -0,0 +1,129 @@
package cn.zhangdeman.filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpFilter;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.annotation.Order;
import java.io.IOException;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
// 初始化请求
@WebFilter("/*") // 所有接口请求均会触发次过滤器
@Order(Ordered.REQUEST_ID) // 足够小, 保证最先执行
public class RequestInitFilter extends HttpFilter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void destroy() {
}
@Override
public void doFilter(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws IOException, ServletException {
RuntimeContext runtimeContext = new RuntimeContext(); // 运行时上下文数据
setBaseInfo(httpServletRequest,httpServletResponse, runtimeContext); // 设置基础信息
setRequestQuery(runtimeContext.getRequestInfo()); // 设置请求query信息
setRequestBody(runtimeContext.getRequestInfo()); // 设置请求Body
setRequestHeaderAndCookie(runtimeContext.getRequestInfo()); // 填充请求信息: header + cookie
setRequestId(runtimeContext); // 设置请求ID, 每次请求需要重新生成
httpServletRequest.setAttribute(RecordField.RUNTIME_THREAD_CONTEXT, runtimeContext); // 记录到请求上下文中
// 继续向后执行
filterChain.doFilter(httpServletRequest, httpServletResponse);
System.out.println("init request do filter 请求执行完成");
}
// 设置基础信息
private void setBaseInfo(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, RuntimeContext runtimeContext) {
// request 信息
Request request = new Request();
request.setHttpServletRequest(httpServletRequest);
request.setClientIp(httpServletRequest.getRemoteAddr()); // client ip
request.setRequestMethod(httpServletRequest.getMethod()); // 请求类型
request.setRequestContentType(httpServletRequest.getContentType()); // 请求类型
request.setRequestUri(httpServletRequest.getRequestURI()); // 请求uri
runtimeContext.setRequestInfo(request); // 请求信息
// server 信息
runtimeContext.setServerIp(httpServletRequest.getLocalAddr()); // 服务器IP
runtimeContext.setServerHostname(httpServletRequest.getLocalName()); // 服务器名称
runtimeContext.setStartTimeStamp(System.currentTimeMillis()); // 开始请求时间
// 响应信息
Response response = new Response();
response.setHttpServletResponse(httpServletResponse);
response.setHeader(new HashMap<>());
response.setCookie(new HashMap<>());
runtimeContext.setResponseInfo(response); // 响应信息
}
// 设置请求Query
private void setRequestQuery(Request request) {
Map<String, String> query = new HashMap<>();
HttpServletRequest httpServletRequest = request.getHttpServletRequest(); // 原始请求实例
Map<String, String[]> queryParamList = httpServletRequest.getParameterMap(); // query参数列表
for (Map.Entry<String, String[]> entity : queryParamList.entrySet()) {
if (entity.getValue().length == 0) {
// 参数值为空
query.put(entity.getKey(), "");
} else {
// 多个参数值, 取第一个
query.put(entity.getKey(), entity.getValue()[0]);
}
}
request.setRequestQuery(query);
}
// 设置请求Body
private void setRequestBody(Request request) throws IOException {
HttpServletRequest httpServletRequest = request.getHttpServletRequest(); // 原始请求实例
ServletInputStream servletInputStream = httpServletRequest.getInputStream();
byte[] requestBody = servletInputStream.readAllBytes();
request.setRequestBodyRaw(requestBody); // 原始请求Body
request.setRequestBody(Arrays.toString(requestBody)); // 请求body
}
// 设置请求信息: header + cookie
private void setRequestHeaderAndCookie(Request request) {
HttpServletRequest httpServletRequest = request.getHttpServletRequest(); // 原始请求实例
request.setRequestHeader(new HashMap<>()); // 请求header
request.setRequestCookie(new HashMap<>()); // 请求cookie
// 全部请求header
Enumeration<String> enumeration = httpServletRequest.getHeaderNames();
while (enumeration.hasMoreElements()) {
String name = enumeration.nextElement();
if (name.equalsIgnoreCase("cookie")) {
// cookie单独摘出来处理
continue;
}
String value = httpServletRequest.getHeader(name);
request.getRequestHeader().put(name, value);
}
// 全部请求cookie
Cookie[] cookieList = httpServletRequest.getCookies();
for (Cookie cookie : cookieList) {
request.getRequestCookie().put(cookie.getName(), cookie.getValue());
}
}
// 设置请求ID
private void setRequestId(RuntimeContext runtimeContext) {
}
// 响应信息
private void setResponse(Response response) {
}
}