mirror of
				https://github.com/continew-org/continew-starter.git
				synced 2025-10-31 22:57:19 +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
	 liquor
					liquor