mirror of
https://github.com/continew-org/continew-starter.git
synced 2025-09-09 20:57:23 +08:00
feat(log/aop): 新增 log-aop 组件模块(基于 AOP 实现日志记录)
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.interceptor.autoconfigure;
|
||||
package top.continew.starter.log.interceptor.annotation;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import top.continew.starter.core.constant.PropertiesConstants;
|
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.interceptor.annotation;
|
||||
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* 日志注解
|
||||
* <p>用于接口方法或类上,辅助 Spring Doc 使用效果最佳</p>
|
||||
*
|
||||
* @author Charles7c
|
||||
* @since 1.1.0
|
||||
*/
|
||||
@Documented
|
||||
@Target({ElementType.METHOD, ElementType.TYPE})
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Log {
|
||||
|
||||
/**
|
||||
* 日志描述(仅用于接口方法上)
|
||||
* <p>
|
||||
* 优先级:@Log("描述") > @Operation(summary="描述")
|
||||
* </p>
|
||||
*/
|
||||
String value() default "";
|
||||
|
||||
/**
|
||||
* 所属模块(用于接口方法或类上)
|
||||
* <p>
|
||||
* 优先级: 接口方法上的 @Log(module = "模块") > 接口类上的 @Log(module = "模块") > @Tag(name = "模块") 内容
|
||||
* </p>
|
||||
*/
|
||||
String module() default "";
|
||||
|
||||
/**
|
||||
* 包含信息(在全局配置基础上扩展包含信息)
|
||||
*/
|
||||
Include[] includes() default {};
|
||||
|
||||
/**
|
||||
* 排除信息(在全局配置基础上减少包含信息)
|
||||
*/
|
||||
Include[] excludes() default {};
|
||||
|
||||
/**
|
||||
* 是否忽略日志记录(用于接口方法或类上)
|
||||
*/
|
||||
boolean ignore() default false;
|
||||
}
|
@@ -28,6 +28,7 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
import top.continew.starter.log.core.dao.LogDao;
|
||||
import top.continew.starter.log.core.dao.impl.LogDaoDefaultImpl;
|
||||
import top.continew.starter.log.interceptor.annotation.ConditionalOnEnabledLog;
|
||||
import top.continew.starter.log.interceptor.handler.LogFilter;
|
||||
import top.continew.starter.log.interceptor.handler.LogInterceptor;
|
||||
|
||||
@@ -75,6 +76,6 @@ public class LogAutoConfiguration implements WebMvcConfigurer {
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Log' completed initialization.");
|
||||
log.debug("[ContiNew Starter] - Auto Configuration 'Log-interceptor' completed initialization.");
|
||||
}
|
||||
}
|
||||
|
@@ -28,7 +28,9 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.web.method.HandlerMethod;
|
||||
import org.springframework.web.servlet.HandlerInterceptor;
|
||||
import top.continew.starter.log.core.annotation.Log;
|
||||
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpRequest;
|
||||
import top.continew.starter.log.core.http.recordable.impl.RecordableServletHttpResponse;
|
||||
import top.continew.starter.log.interceptor.annotation.Log;
|
||||
import top.continew.starter.log.core.dao.LogDao;
|
||||
import top.continew.starter.log.core.enums.Include;
|
||||
import top.continew.starter.log.core.model.LogRecord;
|
||||
|
@@ -1,104 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.interceptor.handler;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.servlet.JakartaServletUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.web.util.ContentCachingRequestWrapper;
|
||||
import org.springframework.web.util.UriUtils;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
import top.continew.starter.core.constant.StringConstants;
|
||||
import top.continew.starter.log.core.model.RecordableHttpRequest;
|
||||
|
||||
import java.net.URI;
|
||||
import java.net.URISyntaxException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 可记录的 HTTP 请求信息适配器
|
||||
*
|
||||
* @author Andy Wilkinson(Spring Boot Actuator)
|
||||
* @author Charles7c
|
||||
*/
|
||||
public final class RecordableServletHttpRequest implements RecordableHttpRequest {
|
||||
|
||||
private final HttpServletRequest request;
|
||||
|
||||
public RecordableServletHttpRequest(HttpServletRequest request) {
|
||||
this.request = request;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getMethod() {
|
||||
return request.getMethod();
|
||||
}
|
||||
|
||||
@Override
|
||||
public URI getUrl() {
|
||||
String queryString = request.getQueryString();
|
||||
if (CharSequenceUtil.isBlank(queryString)) {
|
||||
return URI.create(request.getRequestURL().toString());
|
||||
}
|
||||
try {
|
||||
StringBuilder urlBuilder = this.appendQueryString(queryString);
|
||||
return new URI(urlBuilder.toString());
|
||||
} catch (URISyntaxException e) {
|
||||
String encoded = UriUtils.encodeQuery(queryString, StandardCharsets.UTF_8);
|
||||
StringBuilder urlBuilder = this.appendQueryString(encoded);
|
||||
return URI.create(urlBuilder.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getIp() {
|
||||
return JakartaServletUtil.getClientIP(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getHeaders() {
|
||||
return JakartaServletUtil.getHeaderMap(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBody() {
|
||||
ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class);
|
||||
if (null != wrapper) {
|
||||
String body = StrUtil.utf8Str(wrapper.getContentAsByteArray());
|
||||
return JSONUtil.isTypeJSON(body) ? body : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getParam() {
|
||||
String body = this.getBody();
|
||||
return CharSequenceUtil.isNotBlank(body) && JSONUtil.isTypeJSON(body)
|
||||
? JSONUtil.toBean(body, Map.class)
|
||||
: Collections.unmodifiableMap(request.getParameterMap());
|
||||
}
|
||||
|
||||
private StringBuilder appendQueryString(String queryString) {
|
||||
return new StringBuilder().append(request.getRequestURL())
|
||||
.append(StringConstants.QUESTION_MARK)
|
||||
.append(queryString);
|
||||
}
|
||||
}
|
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2022-present Charles7c Authors. All Rights Reserved.
|
||||
* <p>
|
||||
* Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
* <p>
|
||||
* http://www.gnu.org/licenses/lgpl.html
|
||||
* <p>
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package top.continew.starter.log.interceptor.handler;
|
||||
|
||||
import cn.hutool.core.text.CharSequenceUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.springframework.web.util.ContentCachingResponseWrapper;
|
||||
import org.springframework.web.util.WebUtils;
|
||||
import top.continew.starter.log.core.model.RecordableHttpResponse;
|
||||
import top.continew.starter.web.util.ServletUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 可记录的 HTTP 响应信息适配器
|
||||
*
|
||||
* @author Andy Wilkinson(Spring Boot Actuator)
|
||||
* @author Charles7c
|
||||
*/
|
||||
public final class RecordableServletHttpResponse implements RecordableHttpResponse {
|
||||
|
||||
private final HttpServletResponse response;
|
||||
|
||||
private final int status;
|
||||
|
||||
public RecordableServletHttpResponse(HttpServletResponse response, int status) {
|
||||
this.response = response;
|
||||
this.status = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getStatus() {
|
||||
return this.status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, String> getHeaders() {
|
||||
return ServletUtils.getHeaderMap(response);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBody() {
|
||||
ContentCachingResponseWrapper wrapper = WebUtils
|
||||
.getNativeResponse(response, ContentCachingResponseWrapper.class);
|
||||
if (null != wrapper) {
|
||||
String body = StrUtil.utf8Str(wrapper.getContentAsByteArray());
|
||||
return JSONUtil.isTypeJSON(body) ? body : null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getParam() {
|
||||
String body = this.getBody();
|
||||
return CharSequenceUtil.isNotBlank(body) && JSONUtil.isTypeJSON(body) ? JSONUtil.toBean(body, Map.class) : null;
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user