From 9bf015059b96f41c29f05ecbf7612d611b3a98c3 Mon Sep 17 00:00:00 2001 From: Charles7c Date: Sun, 17 Dec 2023 14:07:44 +0800 Subject: [PATCH] =?UTF-8?q?refactor:=20:boom:=20=E9=80=82=E9=85=8D=20Conti?= =?UTF-8?q?New=20Starter=20Log=EF=BC=88=E6=97=A5=E5=BF=97=E6=A8=A1?= =?UTF-8?q?=E5=9D=97=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1.continew-starter 1.0.1-SNAPSHOT => 1.1.0-SNAPSHOT 2.日志表结构及相关管理 UI 变更 --- .../admin/common/constant/SysConstants.java | 4 +- .../handler/GlobalExceptionHandler.java | 12 - .../admin/common/model/dto/LoginUser.java | 13 +- .../admin/common/util/helper/LoginHelper.java | 11 +- .../common/util/holder/LogContextHolder.java | 87 ---- continew-admin-monitor/pom.xml | 6 + .../admin/monitor/annotation/Log.java | 57 --- ...nfiguration.java => LogConfiguration.java} | 29 +- .../admin/monitor/config/LogDaoLocalImpl.java | 121 ++++++ .../config/properties/LogProperties.java | 57 --- .../admin/monitor/filter/LogFilter.java | 81 ---- .../monitor/interceptor/LogInterceptor.java | 380 ------------------ .../admin/monitor/model/entity/LogDO.java | 32 +- .../monitor/model/resp/LoginLogResp.java | 10 +- .../monitor/model/resp/OperationLogResp.java | 20 +- .../model/resp/SystemLogDetailResp.java | 26 +- .../monitor/model/resp/SystemLogResp.java | 30 +- .../monitor/service/impl/LogServiceImpl.java | 17 - .../admin/auth/model/resp/OnlineUserResp.java | 10 +- continew-admin-ui/src/api/monitor/log.ts | 10 +- continew-admin-ui/src/api/monitor/online.ts | 5 +- .../src/views/monitor/log/login/index.vue | 5 +- .../src/views/monitor/log/operation/index.vue | 4 +- .../src/views/monitor/log/system/index.vue | 108 ++--- .../src/views/monitor/online/index.vue | 5 +- .../user/center/components/operation-log.vue | 4 +- .../admin/webapi/auth/AuthController.java | 7 +- .../webapi/auth/SocialAuthController.java | 2 +- .../admin/webapi/common/CommonController.java | 2 +- .../webapi/common/DashboardController.java | 2 +- .../admin/webapi/monitor/LogController.java | 2 +- .../webapi/system/MessageController.java | 2 +- .../src/main/resources/config/application.yml | 26 +- .../changelog/v1.0.0/continew-admin_table.sql | 12 +- pom.xml | 2 +- 35 files changed, 308 insertions(+), 893 deletions(-) delete mode 100644 continew-admin-common/src/main/java/top/charles7c/continew/admin/common/util/holder/LogContextHolder.java delete mode 100644 continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/annotation/Log.java rename continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/{WebMvcMonitorConfiguration.java => LogConfiguration.java} (56%) create mode 100644 continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/LogDaoLocalImpl.java delete mode 100644 continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/properties/LogProperties.java delete mode 100644 continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/filter/LogFilter.java delete mode 100644 continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/interceptor/LogInterceptor.java diff --git a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/constant/SysConstants.java b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/constant/SysConstants.java index 3ca7f6fe..347d5cb8 100644 --- a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/constant/SysConstants.java +++ b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/constant/SysConstants.java @@ -56,9 +56,9 @@ public class SysConstants { public static final String DEFAULT_PASSWORD = "123456"; /** - * 登录 URI + * 账号登录 URI */ - public static final String LOGIN_URI = "/auth/login"; + public static final String LOGIN_URI = "/auth/account"; /** * 退出 URI diff --git a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/handler/GlobalExceptionHandler.java b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/handler/GlobalExceptionHandler.java index 1ba2b4ad..49c610d0 100644 --- a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/handler/GlobalExceptionHandler.java +++ b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/handler/GlobalExceptionHandler.java @@ -41,7 +41,6 @@ import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.NumberUtil; import cn.hutool.core.util.StrUtil; -import top.charles7c.continew.admin.common.util.holder.LogContextHolder; import top.charles7c.continew.starter.core.constant.StringConstants; import top.charles7c.continew.starter.core.exception.BadRequestException; import top.charles7c.continew.starter.core.exception.BusinessException; @@ -65,7 +64,6 @@ public class GlobalExceptionHandler { @ExceptionHandler(BadRequestException.class) public R handleBadRequestException(BadRequestException e, HttpServletRequest request) { log.warn("请求地址 [{}],自定义验证失败。", request.getRequestURI(), e); - LogContextHolder.setErrorMsg(e.getMessage()); return R.fail(HttpStatus.BAD_REQUEST.value(), e.getMessage()); } @@ -77,7 +75,6 @@ public class GlobalExceptionHandler { log.warn("请求地址 [{}],参数验证失败。", request.getRequestURI(), e); String errorMsg = CollUtil.join(e.getConstraintViolations(), StringConstants.CHINESE_COMMA, ConstraintViolation::getMessage); - LogContextHolder.setErrorMsg(errorMsg); return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } @@ -89,7 +86,6 @@ public class GlobalExceptionHandler { log.warn("请求地址 [{}],参数验证失败。", request.getRequestURI(), e); String errorMsg = CollUtil.join(e.getAllErrors(), StringConstants.CHINESE_COMMA, DefaultMessageSourceResolvable::getDefaultMessage); - LogContextHolder.setErrorMsg(errorMsg); return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } @@ -101,7 +97,6 @@ public class GlobalExceptionHandler { log.warn("请求地址 [{}],参数验证失败。", request.getRequestURI(), e); String errorMsg = ExceptionUtils .exToNull(() -> Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage()); - LogContextHolder.setErrorMsg(errorMsg); return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } @@ -113,7 +108,6 @@ public class GlobalExceptionHandler { HttpServletRequest request) { String errorMsg = StrUtil.format("参数名:[{}],期望参数类型:[{}]", e.getName(), e.getParameter().getParameterType()); log.warn("请求地址 [{}],参数转换失败,{}。", request.getRequestURI(), errorMsg, e); - LogContextHolder.setErrorMsg(errorMsg); return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } @@ -125,7 +119,6 @@ public class GlobalExceptionHandler { log.warn("请求地址 [{}],上传文件失败,文件大小超过限制。", request.getRequestURI(), e); String sizeLimit = StrUtil.subBetween(e.getMessage(), "The maximum size ", " for"); String errorMsg = String.format("请上传小于 %sMB 的文件", NumberUtil.parseLong(sizeLimit) / 1024 / 1024); - LogContextHolder.setErrorMsg(errorMsg); return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } @@ -140,7 +133,6 @@ public class GlobalExceptionHandler { case NotLoginException.BE_REPLACED_MESSAGE -> "您已被顶下线。"; default -> "您的登录状态已过期,请重新登录。"; }; - LogContextHolder.setErrorMsg(errorMsg); return R.fail(HttpStatus.UNAUTHORIZED.value(), errorMsg); } @@ -167,7 +159,6 @@ public class GlobalExceptionHandler { */ @ExceptionHandler(HttpRequestMethodNotSupportedException.class) public R handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e, HttpServletRequest request) { - LogContextHolder.setErrorMsg(e.getMessage()); log.error("请求地址 [{}],不支持 [{}] 请求。", request.getRequestURI(), e.getMethod()); return R.fail(HttpStatus.METHOD_NOT_ALLOWED.value(), e.getMessage()); } @@ -178,7 +169,6 @@ public class GlobalExceptionHandler { @ExceptionHandler(BusinessException.class) public R handleServiceException(BusinessException e, HttpServletRequest request) { log.error("请求地址 [{}],发生业务异常。", request.getRequestURI(), e); - LogContextHolder.setErrorMsg(e.getMessage()); return R.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()); } @@ -188,7 +178,6 @@ public class GlobalExceptionHandler { @ExceptionHandler(RuntimeException.class) public R handleRuntimeException(RuntimeException e, HttpServletRequest request) { log.error("请求地址 [{}],发生系统异常。", request.getRequestURI(), e); - LogContextHolder.setException(e); return R.fail(e.getMessage()); } @@ -198,7 +187,6 @@ public class GlobalExceptionHandler { @ExceptionHandler(Throwable.class) public R handleException(Throwable e, HttpServletRequest request) { log.error("请求地址 [{}],发生未知异常。", request.getRequestURI(), e); - LogContextHolder.setException(e); return R.fail(e.getMessage()); } } \ No newline at end of file diff --git a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/model/dto/LoginUser.java b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/model/dto/LoginUser.java index 47a407aa..c7b8da57 100644 --- a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/model/dto/LoginUser.java +++ b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/model/dto/LoginUser.java @@ -75,20 +75,25 @@ public class LoginUser implements Serializable { private String token; /** - * 登录 IP + * IP */ - private String clientIp; + private String ip; /** - * 登录地点 + * IP 归属地 */ - private String location; + private String address; /** * 浏览器 */ private String browser; + /** + * 操作系统 + */ + private String os; + /** * 登录时间 */ diff --git a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/util/helper/LoginHelper.java b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/util/helper/LoginHelper.java index 73662554..91d2a7ae 100644 --- a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/util/helper/LoginHelper.java +++ b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/util/helper/LoginHelper.java @@ -26,13 +26,12 @@ import lombok.NoArgsConstructor; import cn.dev33.satoken.context.SaHolder; import cn.dev33.satoken.session.SaSession; import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.util.StrUtil; import cn.hutool.extra.servlet.JakartaServletUtil; import cn.hutool.extra.spring.SpringUtil; import top.charles7c.continew.admin.common.constant.CacheConstants; -import top.charles7c.continew.admin.common.model.dto.LogContext; import top.charles7c.continew.admin.common.model.dto.LoginUser; -import top.charles7c.continew.admin.common.util.holder.LogContextHolder; import top.charles7c.continew.starter.core.util.ExceptionUtils; import top.charles7c.continew.starter.core.util.IpUtils; import top.charles7c.continew.starter.core.util.ServletUtils; @@ -58,11 +57,11 @@ public class LoginHelper { public static String login(LoginUser loginUser) { // 记录登录信息 HttpServletRequest request = ServletUtils.getRequest(); - loginUser.setClientIp(JakartaServletUtil.getClientIP(request)); - loginUser.setLocation(IpUtils.getCityInfo(loginUser.getClientIp())); + loginUser.setIp(JakartaServletUtil.getClientIP(request)); + loginUser.setAddress(IpUtils.getAddress(loginUser.getIp())); loginUser.setBrowser(ServletUtils.getBrowser(request)); - LogContext logContext = LogContextHolder.get(); - loginUser.setLoginTime(null != logContext ? logContext.getCreateTime() : LocalDateTime.now()); + loginUser.setLoginTime(LocalDateTime.now()); + loginUser.setOs(StrUtil.subBefore(ServletUtils.getOs(request), " or", false)); // 登录并缓存用户信息 StpUtil.login(loginUser.getId()); SaHolder.getStorage().set(CacheConstants.LOGIN_USER_KEY, loginUser); diff --git a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/util/holder/LogContextHolder.java b/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/util/holder/LogContextHolder.java deleted file mode 100644 index fd8a0453..00000000 --- a/continew-admin-common/src/main/java/top/charles7c/continew/admin/common/util/holder/LogContextHolder.java +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.charles7c.continew.admin.common.util.holder; - -import lombok.AccessLevel; -import lombok.NoArgsConstructor; - -import top.charles7c.continew.admin.common.model.dto.LogContext; - -/** - * 系统日志上下文持有者 - * - * @author Charles7c - * @since 2022/12/25 8:55 - */ -@NoArgsConstructor(access = AccessLevel.PRIVATE) -public class LogContextHolder { - - private static final ThreadLocal LOG_THREAD_LOCAL = new ThreadLocal<>(); - - /** - * 存储系统日志上下文 - * - * @param logContext - * 系统日志上下文信息 - */ - public static void set(LogContext logContext) { - LOG_THREAD_LOCAL.set(logContext); - } - - /** - * 获取系统日志上下文 - * - * @return 系统日志上下文信息 - */ - public static LogContext get() { - return LOG_THREAD_LOCAL.get(); - } - - /** - * 移除系统日志上下文 - */ - public static void remove() { - LOG_THREAD_LOCAL.remove(); - } - - /** - * 在系统日志上下文中保存异常信息 - * - * @param e - * 异常信息 - */ - public static void setException(Throwable e) { - LogContext logContext = get(); - if (null != logContext) { - logContext.setErrorMsg(e.getMessage()); - logContext.setException(e); - } - } - - /** - * 在系统日志上下文中保存错误信息(非未知异常不记录异常信息,只记录错误信息) - * - * @param errorMsg - * 错误信息 - */ - public static void setErrorMsg(String errorMsg) { - LogContext logContext = get(); - if (null != logContext) { - logContext.setErrorMsg(errorMsg); - } - } -} diff --git a/continew-admin-monitor/pom.xml b/continew-admin-monitor/pom.xml index 29756b08..bdc88865 100644 --- a/continew-admin-monitor/pom.xml +++ b/continew-admin-monitor/pom.xml @@ -16,6 +16,12 @@ 系统监控模块(存放系统监控模块相关功能,例如:日志管理、服务监控等) + + + top.charles7c.continew + continew-starter-log-httptrace-pro + + top.charles7c.continew diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/annotation/Log.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/annotation/Log.java deleted file mode 100644 index be9f3d66..00000000 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/annotation/Log.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.charles7c.continew.admin.monitor.annotation; - -import java.lang.annotation.*; - -/** - * 系统日志注解(用于接口方法或类上,辅助 Spring Doc OpenAPI3 使用效果最佳) - * - * @author Charles7c - * @since 2022/12/23 20:00 - */ -@Documented -@Target({ElementType.METHOD, ElementType.TYPE}) -@Retention(RetentionPolicy.RUNTIME) -public @interface Log { - - /** - * 日志描述(仅用于接口方法上) - *

- * 读取顺序:(越靠后优先级越高)
- * 1、读取对应接口方法上的 @Operation(summary="描述") 内容
- * 2、读取对应接口方法上的 @Log("描述") 内容
- *

- */ - String value() default ""; - - /** - * 所属模块(用于接口方法或类上) - *

- * 读取顺序:(越靠后优先级越高)
- * 1、读取对应接口类上的 @Tag(name = "模块") 内容
- * 2、读取对应接口类上的 @Log(module = "模块") 内容
- * 3、读取对应接口方法上的 @Log(module = "模块") 内容 - *

- */ - String module() default ""; - - /** - * 是否忽略日志记录(用于接口方法或类上) - */ - boolean ignore() default false; -} diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/WebMvcMonitorConfiguration.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/LogConfiguration.java similarity index 56% rename from continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/WebMvcMonitorConfiguration.java rename to continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/LogConfiguration.java index 0343cb80..24de8a3d 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/WebMvcMonitorConfiguration.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/LogConfiguration.java @@ -16,30 +16,29 @@ package top.charles7c.continew.admin.monitor.config; -import lombok.RequiredArgsConstructor; - +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.web.servlet.config.annotation.EnableWebMvc; -import org.springframework.web.servlet.config.annotation.InterceptorRegistry; -import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; -import top.charles7c.continew.admin.monitor.interceptor.LogInterceptor; +import top.charles7c.continew.admin.monitor.mapper.LogMapper; +import top.charles7c.continew.admin.system.service.UserService; +import top.charles7c.continew.starter.log.common.dao.LogDao; +import top.charles7c.continew.starter.log.httptracepro.autoconfigure.ConditionalOnEnabledLog; /** - * 监控模块 Web MVC 配置 + * 日志配置 * * @author Charles7c * @since 2022/12/24 23:15 */ -@EnableWebMvc @Configuration -@RequiredArgsConstructor -public class WebMvcMonitorConfiguration implements WebMvcConfigurer { +@ConditionalOnEnabledLog +public class LogConfiguration { - private final LogInterceptor logInterceptor; - - @Override - public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(logInterceptor); + /** + * 日志持久层接口本地实现类 + */ + @Bean + public LogDao logDao(UserService userService, LogMapper logMapper) { + return new LogDaoLocalImpl(userService, logMapper); } } diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/LogDaoLocalImpl.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/LogDaoLocalImpl.java new file mode 100644 index 00000000..915cf905 --- /dev/null +++ b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/LogDaoLocalImpl.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * 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.charles7c.continew.admin.monitor.config; + +import java.time.LocalDateTime; +import java.time.ZoneId; +import java.util.List; +import java.util.Map; + +import lombok.RequiredArgsConstructor; + +import org.springframework.http.HttpHeaders; +import org.springframework.scheduling.annotation.Async; + +import cn.dev33.satoken.SaManager; +import cn.dev33.satoken.stp.StpUtil; +import cn.hutool.core.convert.Convert; +import cn.hutool.core.map.MapUtil; +import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpStatus; +import cn.hutool.json.JSONUtil; + +import top.charles7c.continew.admin.auth.model.req.AccountLoginReq; +import top.charles7c.continew.admin.common.constant.SysConstants; +import top.charles7c.continew.admin.monitor.enums.LogStatusEnum; +import top.charles7c.continew.admin.monitor.mapper.LogMapper; +import top.charles7c.continew.admin.monitor.model.entity.LogDO; +import top.charles7c.continew.admin.system.service.UserService; +import top.charles7c.continew.starter.core.constant.StringConstants; +import top.charles7c.continew.starter.core.util.ExceptionUtils; +import top.charles7c.continew.starter.extension.crud.model.resp.R; +import top.charles7c.continew.starter.log.common.dao.LogDao; +import top.charles7c.continew.starter.log.common.model.LogRecord; +import top.charles7c.continew.starter.log.common.model.LogRequest; +import top.charles7c.continew.starter.log.common.model.LogResponse; + +/** + * 日志持久层接口本地实现类 + * + * @author Charles7c + * @since 2023/12/16 23:55 + */ +@RequiredArgsConstructor +public class LogDaoLocalImpl implements LogDao { + + private final UserService userService; + private final LogMapper logMapper; + + @Async + @Override + public void add(LogRecord logRecord) { + LogDO logDO = new LogDO(); + logDO.setDescription(logRecord.getDescription()); + String module = logRecord.getModule(); + logDO.setModule( + StrUtil.isNotBlank(module) ? logRecord.getModule().replace("API", StringConstants.EMPTY).trim() : null); + logDO.setCreateTime(LocalDateTime.ofInstant(logRecord.getTimestamp(), ZoneId.systemDefault())); + logDO.setTimeTaken(logRecord.getTimeTaken().toMillis()); + // 请求信息 + LogRequest logRequest = logRecord.getRequest(); + logDO.setRequestMethod(logRequest.getMethod()); + String requestUrl = logRequest.getUri().toString(); + logDO.setRequestUrl(requestUrl); + Map> requestHeaders = logRequest.getHeaders(); + logDO.setRequestHeaders(JSONUtil.toJsonStr(requestHeaders)); + String requestBody = logRequest.getBody(); + logDO.setRequestBody(requestBody); + logDO.setIp(logRequest.getIp()); + logDO.setAddress(logRequest.getAddress()); + logDO.setBrowser(logRequest.getBrowser()); + logDO.setOs(StrUtil.subBefore(logRequest.getOs(), " or", false)); + // 响应信息 + LogResponse logResponse = logRecord.getResponse(); + Integer statusCode = logResponse.getStatus(); + logDO.setStatusCode(statusCode); + logDO.setResponseHeaders(JSONUtil.toJsonStr(logResponse.getHeaders())); + String responseBody = logResponse.getBody(); + logDO.setResponseBody(responseBody); + // 状态 + logDO.setStatus(statusCode >= HttpStatus.HTTP_BAD_REQUEST ? LogStatusEnum.FAILURE : LogStatusEnum.SUCCESS); + if (StrUtil.isNotBlank(responseBody) && JSONUtil.isTypeJSON(responseBody)) { + R result = JSONUtil.toBean(responseBody, R.class); + if (!result.isSuccess()) { + logDO.setStatus(LogStatusEnum.FAILURE); + logDO.setErrorMsg(result.getMsg()); + } + // 操作人 + if (StrUtil.contains(requestUrl, SysConstants.LOGOUT_URI)) { + Long loginId = Convert.toLong(result.getData(), -1L); + logDO.setCreateUser(-1 != loginId ? loginId : null); + } + } + // 操作人 + if (StrUtil.contains(requestUrl, SysConstants.LOGIN_URI)) { + AccountLoginReq loginReq = JSONUtil.toBean(requestBody, AccountLoginReq.class); + logDO.setCreateUser( + ExceptionUtils.exToNull(() -> userService.getByUsername(loginReq.getUsername()).getId())); + } else if (!StrUtil.contains(requestUrl, SysConstants.LOGOUT_URI) && MapUtil.isNotEmpty(requestHeaders) + && requestHeaders.containsKey(HttpHeaders.AUTHORIZATION)) { + String authorization = requestHeaders.get(HttpHeaders.AUTHORIZATION).get(0); + String token = authorization.replace(SaManager.getConfig().getTokenPrefix() + StringConstants.SPACE, + StringConstants.EMPTY); + logDO.setCreateUser(Convert.toLong(StpUtil.getLoginIdByToken(token))); + } + logMapper.insert(logDO); + } +} diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/properties/LogProperties.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/properties/LogProperties.java deleted file mode 100644 index 007b2101..00000000 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/config/properties/LogProperties.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.charles7c.continew.admin.monitor.config.properties; - -import java.util.ArrayList; -import java.util.List; - -import lombok.Data; - -import org.springframework.boot.context.properties.ConfigurationProperties; -import org.springframework.stereotype.Component; - -/** - * 系统日志配置属性 - * - * @author Charles7c - * @since 2022/12/24 23:04 - */ -@Data -@Component -@ConfigurationProperties(prefix = "logging.system") -public class LogProperties { - - /** - * 是否启用系统日志 - */ - private Boolean enabled; - - /** - * 是否记录内网 IP 操作 - */ - private Boolean includeInnerIp; - - /** - * 排除请求方式(哪些请求方式不记录系统日志) - */ - private List excludeMethods = new ArrayList<>(); - - /** - * 脱敏字段 - */ - private List desensitizeFields = new ArrayList<>(); -} diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/filter/LogFilter.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/filter/LogFilter.java deleted file mode 100644 index 5746bce8..00000000 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/filter/LogFilter.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.charles7c.continew.admin.monitor.filter; - -import java.io.IOException; -import java.util.Objects; - -import jakarta.servlet.FilterChain; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import org.springframework.core.Ordered; -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Component; -import org.springframework.web.filter.OncePerRequestFilter; -import org.springframework.web.util.ContentCachingRequestWrapper; -import org.springframework.web.util.ContentCachingResponseWrapper; -import org.springframework.web.util.WebUtils; - -/** - * 系统日志过滤器(缓存请求和响应体过滤器) - * - *

- * 由于 requestBody 和 responseBody 分别对应的是 InputStream 和 OutputStream,由于流的特性,读取完之后就无法再被使用了。 所以,需要额外缓存一次流信息。 - *

- * - * @author Charles7c - * @since 2022/12/24 21:16 - */ -@Component -public class LogFilter extends OncePerRequestFilter implements Ordered { - - @Override - public int getOrder() { - return Ordered.LOWEST_PRECEDENCE - 10; - } - - @Override - protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, - @NonNull FilterChain filterChain) throws ServletException, IOException { - // 包装流,可重复读取 - if (!(request instanceof ContentCachingRequestWrapper)) { - request = new ContentCachingRequestWrapper(request); - } - if (!(response instanceof ContentCachingResponseWrapper)) { - response = new ContentCachingResponseWrapper(response); - } - - filterChain.doFilter(request, response); - updateResponse(response); - } - - /** - * 更新响应(不操作这一步,会导致接口响应空白) - * - * @param response - * 响应对象 - * @throws IOException - * / - */ - private void updateResponse(HttpServletResponse response) throws IOException { - ContentCachingResponseWrapper responseWrapper = - WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class); - Objects.requireNonNull(responseWrapper).copyBodyToResponse(); - } -} diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/interceptor/LogInterceptor.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/interceptor/LogInterceptor.java deleted file mode 100644 index 6f2ca45f..00000000 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/interceptor/LogInterceptor.java +++ /dev/null @@ -1,380 +0,0 @@ -/* - * Copyright (c) 2022-present Charles7c Authors. All Rights Reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * 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.charles7c.continew.admin.monitor.interceptor; - -import java.time.LocalDateTime; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import io.swagger.v3.oas.annotations.Operation; -import io.swagger.v3.oas.annotations.tags.Tag; - -import org.springframework.lang.NonNull; -import org.springframework.stereotype.Component; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.HandlerInterceptor; -import org.springframework.web.util.ContentCachingRequestWrapper; -import org.springframework.web.util.ContentCachingResponseWrapper; -import org.springframework.web.util.WebUtils; - -import cn.hutool.core.collection.CollUtil; -import cn.hutool.core.date.LocalDateTimeUtil; -import cn.hutool.core.exceptions.ExceptionUtil; -import cn.hutool.core.util.ObjectUtil; -import cn.hutool.core.util.StrUtil; -import cn.hutool.extra.servlet.JakartaServletUtil; -import cn.hutool.extra.spring.SpringUtil; -import cn.hutool.http.HttpStatus; -import cn.hutool.json.JSONArray; -import cn.hutool.json.JSONObject; -import cn.hutool.json.JSONUtil; - -import top.charles7c.continew.admin.auth.model.req.AccountLoginReq; -import top.charles7c.continew.admin.common.constant.SysConstants; -import top.charles7c.continew.admin.common.model.dto.LogContext; -import top.charles7c.continew.admin.common.util.helper.LoginHelper; -import top.charles7c.continew.admin.common.util.holder.LogContextHolder; -import top.charles7c.continew.admin.monitor.annotation.Log; -import top.charles7c.continew.admin.monitor.config.properties.LogProperties; -import top.charles7c.continew.admin.monitor.enums.LogStatusEnum; -import top.charles7c.continew.admin.monitor.model.entity.LogDO; -import top.charles7c.continew.admin.system.service.UserService; -import top.charles7c.continew.starter.core.constant.StringConstants; -import top.charles7c.continew.starter.core.util.ExceptionUtils; -import top.charles7c.continew.starter.core.util.IpUtils; -import top.charles7c.continew.starter.core.util.ServletUtils; -import top.charles7c.continew.starter.extension.crud.model.resp.R; - -/** - * 系统日志拦截器 - * - * @author Charles7c - * @since 2022/12/24 21:14 - */ -@Slf4j -@Component -@RequiredArgsConstructor -public class LogInterceptor implements HandlerInterceptor { - - private final UserService userService; - private final LogProperties operationLogProperties; - private static final String ENCRYPT_SYMBOL = "****************"; - - @Override - public boolean preHandle(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, - @NonNull Object handler) { - if (this.isNeedRecord(handler, request)) { - // 记录时间 - this.logCreateTime(); - } - return true; - } - - @Override - public void afterCompletion(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, - @NonNull Object handler, Exception e) { - // 记录请求耗时及异常信息 - LogDO logDO = this.logElapsedTimeAndException(); - if (null == logDO) { - return; - } - HandlerMethod handlerMethod = (HandlerMethod)handler; - // 记录所属模块 - this.logModule(logDO, handlerMethod); - // 记录日志描述 - this.logDescription(logDO, handlerMethod); - // 记录请求信息 - this.logRequest(logDO, request); - // 记录响应信息 - this.logResponse(logDO, response); - // 保存系统日志 - SpringUtil.getApplicationContext().publishEvent(logDO); - } - - /** - * 记录时间 - */ - private void logCreateTime() { - LogContext logContext = new LogContext(); - logContext.setCreateUser(LoginHelper.getUserId()); - logContext.setCreateTime(LocalDateTime.now()); - LogContextHolder.set(logContext); - } - - /** - * 记录请求耗时及异常详情 - * - * @return 系统日志信息 - */ - private LogDO logElapsedTimeAndException() { - LogContext logContext = LogContextHolder.get(); - if (null == logContext) { - return null; - } - try { - LogDO logDO = new LogDO(); - logDO.setCreateTime(logContext.getCreateTime()); - logDO.setElapsedTime(System.currentTimeMillis() - LocalDateTimeUtil.toEpochMilli(logDO.getCreateTime())); - logDO.setStatus(LogStatusEnum.SUCCESS); - // 记录错误信息(非未知异常不记录异常详情,只记录错误信息) - String errorMsg = logContext.getErrorMsg(); - if (StrUtil.isNotBlank(errorMsg)) { - logDO.setStatus(LogStatusEnum.FAILURE); - logDO.setErrorMsg(errorMsg); - } - // 记录异常详情 - Throwable exception = logContext.getException(); - if (null != exception) { - logDO.setStatus(LogStatusEnum.FAILURE); - logDO.setExceptionDetail(ExceptionUtil.stacktraceToString(exception, -1)); - } - return logDO; - } finally { - LogContextHolder.remove(); - } - } - - /** - * 记录所属模块 - * - * @param logDO - * 系统日志信息 - * @param handlerMethod - * 处理器方法 - */ - private void logModule(LogDO logDO, HandlerMethod handlerMethod) { - Tag classTag = handlerMethod.getBeanType().getDeclaredAnnotation(Tag.class); - Log classLog = handlerMethod.getBeanType().getDeclaredAnnotation(Log.class); - Log methodLog = handlerMethod.getMethodAnnotation(Log.class); - // 例如:@Tag(name = "部门管理") -> 部门管理 - // (本框架代码规范)例如:@Tag(name = "部门管理 API") -> 部门管理 - if (null != classTag) { - String name = classTag.name(); - logDO.setModule( - StrUtil.isNotBlank(name) ? name.replace("API", StringConstants.EMPTY).trim() : "请在该接口类上指定所属模块"); - } - // 例如:@Log(module = "部门管理") -> 部门管理 - if (null != classLog && StrUtil.isNotBlank(classLog.module())) { - logDO.setModule(classLog.module()); - } - if (null != methodLog && StrUtil.isNotBlank(methodLog.module())) { - logDO.setModule(methodLog.module()); - } - } - - /** - * 记录日志描述 - * - * @param logDO - * 系统日志信息 - * @param handlerMethod - * 处理器方法 - */ - private void logDescription(LogDO logDO, HandlerMethod handlerMethod) { - Operation methodOperation = handlerMethod.getMethodAnnotation(Operation.class); - Log methodLog = handlerMethod.getMethodAnnotation(Log.class); - // 例如:@Operation(summary="新增部门") -> 新增部门 - if (null != methodOperation) { - logDO.setDescription(StrUtil.blankToDefault(methodOperation.summary(), "请在该接口方法上指定日志描述")); - } - // 例如:@Log("新增部门") -> 新增部门 - if (null != methodLog && StrUtil.isNotBlank(methodLog.value())) { - logDO.setDescription(methodLog.value()); - } - } - - /** - * 记录请求信息 - * - * @param logDO - * 系统日志信息 - * @param request - * 请求对象 - */ - private void logRequest(LogDO logDO, HttpServletRequest request) { - logDO.setRequestUrl(StrUtil.isBlank(request.getQueryString()) ? request.getRequestURL().toString() : request - .getRequestURL().append(StringConstants.QUESTION_MARK).append(request.getQueryString()).toString()); - String method = request.getMethod(); - logDO.setRequestMethod(method); - logDO.setRequestHeaders(this.desensitize(JakartaServletUtil.getHeaderMap(request))); - String requestBody = this.getRequestBody(request); - logDO.setCreateUser(ObjectUtil.defaultIfNull(logDO.getCreateUser(), LoginHelper.getUserId())); - String requestURI = request.getRequestURI(); - if (requestURI.startsWith("/oauth")) { - logDO.setCreateUser(null); - } - if (null == logDO.getCreateUser() && SysConstants.LOGIN_URI.equals(requestURI)) { - AccountLoginReq loginReq = JSONUtil.toBean(requestBody, AccountLoginReq.class); - logDO.setCreateUser( - ExceptionUtils.exToNull(() -> userService.getByUsername(loginReq.getUsername()).getId())); - } - if (StrUtil.isNotBlank(requestBody)) { - if (JSONUtil.isTypeJSONObject(requestBody)) { - requestBody = this.desensitize(JSONUtil.parseObj(requestBody)); - } else if (JSONUtil.isTypeJSONArray(requestBody)) { - JSONArray requestBodyJsonArr = JSONUtil.parseArray(requestBody); - List requestBodyJsonObjList = new ArrayList<>(requestBodyJsonArr.size()); - for (Object requestBodyJsonObj : requestBodyJsonArr) { - requestBodyJsonObjList - .add(JSONUtil.parseObj(this.desensitize(JSONUtil.parseObj(requestBodyJsonObj)))); - } - requestBody = JSONUtil.toJsonStr(requestBodyJsonObjList); - } else { - requestBody = this.desensitize(JakartaServletUtil.getParamMap(request)); - } - logDO.setRequestBody(requestBody); - } - logDO.setClientIp(JakartaServletUtil.getClientIP(request)); - logDO.setLocation(IpUtils.getCityInfo(logDO.getClientIp())); - logDO.setBrowser(ServletUtils.getBrowser(request)); - } - - /** - * 记录响应信息 - * - * @param logDO - * 系统日志信息 - * @param response - * 响应对象 - */ - private void logResponse(LogDO logDO, HttpServletResponse response) { - int status = response.getStatus(); - logDO.setStatusCode(status); - logDO.setStatus(status >= HttpStatus.HTTP_BAD_REQUEST ? LogStatusEnum.FAILURE : logDO.getStatus()); - logDO.setResponseHeaders(this.desensitize(JakartaServletUtil.getHeadersMap(response))); - // 响应体(不记录非 JSON 响应数据) - String responseBody = this.getResponseBody(response); - if (StrUtil.isNotBlank(responseBody) && JSONUtil.isTypeJSON(responseBody)) { - logDO.setResponseBody(responseBody); - // 业务状态码优先级高 - try { - R result = JSONUtil.toBean(responseBody, R.class); - logDO.setStatusCode(result.getCode()); - logDO.setStatus(result.isSuccess() ? LogStatusEnum.SUCCESS : LogStatusEnum.FAILURE); - } catch (Exception ignored) { - } - } - } - - /** - * 数据脱敏 - * - * @param waitDesensitizeData - * 待脱敏数据 - * @return 脱敏后的 JSON 字符串数据 - */ - @SuppressWarnings("unchecked") - private String desensitize(Map waitDesensitizeData) { - String desensitizeDataStr = JSONUtil.toJsonStr(waitDesensitizeData); - try { - if (CollUtil.isEmpty(waitDesensitizeData)) { - return desensitizeDataStr; - } - for (String desensitizeProperty : operationLogProperties.getDesensitizeFields()) { - waitDesensitizeData.computeIfPresent(desensitizeProperty, (k, v) -> ENCRYPT_SYMBOL); - waitDesensitizeData.computeIfPresent(desensitizeProperty.toLowerCase(), (k, v) -> ENCRYPT_SYMBOL); - waitDesensitizeData.computeIfPresent(desensitizeProperty.toUpperCase(), (k, v) -> ENCRYPT_SYMBOL); - } - return JSONUtil.toJsonStr(waitDesensitizeData); - } catch (Exception ignored) { - } - return desensitizeDataStr; - } - - /** - * 获取请求体 - * - * @param request - * 请求对象 - * @return 请求体 - */ - private String getRequestBody(HttpServletRequest request) { - String requestBody = ""; - ContentCachingRequestWrapper wrapper = WebUtils.getNativeRequest(request, ContentCachingRequestWrapper.class); - if (null != wrapper) { - requestBody = StrUtil.utf8Str(wrapper.getContentAsByteArray()); - } - return requestBody; - } - - /** - * 获取响应体 - * - * @param response - * 响应对象 - * @return 响应体 - */ - private String getResponseBody(HttpServletResponse response) { - String responseBody = ""; - ContentCachingResponseWrapper wrapper = - WebUtils.getNativeResponse(response, ContentCachingResponseWrapper.class); - if (null != wrapper) { - responseBody = StrUtil.utf8Str(wrapper.getContentAsByteArray()); - } - return responseBody; - } - - /** - * 是否要记录系统日志 - * - * @param handler - * 处理器 - * @param request - * 请求对象 - * @return true 需要记录;false 不需要记录 - */ - private boolean isNeedRecord(Object handler, HttpServletRequest request) { - // 1、未启用时,不需要记录系统日志 - if (!(handler instanceof HandlerMethod) || Boolean.FALSE.equals(operationLogProperties.getEnabled())) { - return false; - } - // 2、检查是否需要记录内网 IP 操作 - boolean isInnerIp = IpUtils.isInnerIp(JakartaServletUtil.getClientIP(request)); - if (isInnerIp && Boolean.FALSE.equals(operationLogProperties.getIncludeInnerIp())) { - return false; - } - // 3、排除不需要记录系统日志的接口 - HandlerMethod handlerMethod = (HandlerMethod)handler; - Log methodLog = handlerMethod.getMethodAnnotation(Log.class); - // 3.1 如果接口方法上既没有 @Log 注解,也没有 @Operation 注解,则不记录系统日志 - Operation methodOperation = handlerMethod.getMethodAnnotation(Operation.class); - if (null == methodLog && null == methodOperation) { - return false; - } - // 3.2 请求方式不要求记录且接口方法上没有 @Log 注解,则不记录系统日志 - if (null == methodLog && operationLogProperties.getExcludeMethods().contains(request.getMethod())) { - return false; - } - // 3.3 如果接口被隐藏,不记录系统日志 - if (null != methodOperation && methodOperation.hidden()) { - return false; - } - // 3.4 如果接口方法或类上有 @Log 注解,但是要求忽略该接口,则不记录系统日志 - if (null != methodLog && methodLog.ignore()) { - return false; - } - Log classLog = handlerMethod.getBeanType().getDeclaredAnnotation(Log.class); - return null == classLog || !classLog.ignore(); - } -} diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/entity/LogDO.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/entity/LogDO.java index 7c5bbd11..31ef685d 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/entity/LogDO.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/entity/LogDO.java @@ -92,40 +92,40 @@ public class LogDO implements Serializable { private String responseBody; /** - * 请求耗时(ms) + * 耗时(ms) */ - private Long elapsedTime; + private Long timeTaken; /** - * 操作状态 + * IP */ - private LogStatusEnum status; + private String ip; /** - * 客户端IP + * IP 归属地 */ - private String clientIp; - - /** - * IP归属地 - */ - private String location; + private String address; /** * 浏览器 */ private String browser; + /** + * 操作系统 + */ + private String os; + + /** + * 状态 + */ + private LogStatusEnum status; + /** * 错误信息 */ private String errorMsg; - /** - * 异常详情 - */ - private String exceptionDetail; - /** * 创建人 */ diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/LoginLogResp.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/LoginLogResp.java index 95ee0b9a..919b53e7 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/LoginLogResp.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/LoginLogResp.java @@ -53,13 +53,13 @@ public class LoginLogResp extends LogResp { * 登录 IP */ @Schema(description = "登录 IP", example = "192.168.0.1") - private String clientIp; + private String ip; /** * 登录地点 */ @Schema(description = "登录地点", example = "中国北京北京市") - private String location; + private String address; /** * 浏览器 @@ -67,6 +67,12 @@ public class LoginLogResp extends LogResp { @Schema(description = "浏览器", example = "Chrome 115.0.0.0") private String browser; + /** + * 操作系统 + */ + @Schema(description = "操作系统", example = "Windows 10") + private String os; + /** * 错误信息 */ diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/OperationLogResp.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/OperationLogResp.java index 42a9a13b..a470a1ca 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/OperationLogResp.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/OperationLogResp.java @@ -50,22 +50,16 @@ public class OperationLogResp extends LogResp { private String module; /** - * 操作状态 + * 操作 IP */ - @Schema(description = "操作状态(1:成功;2:失败)", type = "Integer", allowableValues = {"1", "2"}, example = "1") - private LogStatusEnum status; - - /** - * 操作IP - */ - @Schema(description = "操作IP", example = "192.168.0.1") - private String clientIp; + @Schema(description = "操作 IP", example = "192.168.0.1") + private String ip; /** * 操作地点 */ @Schema(description = "操作地点", example = "中国北京北京市") - private String location; + private String address; /** * 浏览器 @@ -73,6 +67,12 @@ public class OperationLogResp extends LogResp { @Schema(description = "浏览器", example = "Chrome 115.0.0.0") private String browser; + /** + * 操作状态 + */ + @Schema(description = "操作状态(1:成功;2:失败)", type = "Integer", allowableValues = {"1", "2"}, example = "1") + private LogStatusEnum status; + /** * 错误信息 */ diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/SystemLogDetailResp.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/SystemLogDetailResp.java index ddf14d5c..05160e26 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/SystemLogDetailResp.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/SystemLogDetailResp.java @@ -56,7 +56,7 @@ public class SystemLogDetailResp extends LogResp { /** * 请求头 */ - @Schema(description = "请求头", example = "{\"Origin\": \"https://cnadmin.charles7c.top\",...}") + @Schema(description = "请求头", example = "{\"Origin\": [\"https://cnadmin.charles7c.top\"],...}") private String requestHeaders; /** @@ -78,16 +78,16 @@ public class SystemLogDetailResp extends LogResp { private String responseBody; /** - * 客户端IP + * IP */ - @Schema(description = "客户端IP", example = "192.168.0.1") - private String clientIp; + @Schema(description = "IP", example = "192.168.0.1") + private String ip; /** - * IP归属地 + * 地址 */ - @Schema(description = "IP归属地", example = "中国北京北京市") - private String location; + @Schema(description = "地址", example = "中国北京北京市") + private String address; /** * 浏览器 @@ -96,8 +96,14 @@ public class SystemLogDetailResp extends LogResp { private String browser; /** - * 请求耗时(ms) + * 操作系统 */ - @Schema(description = "请求耗时(ms)", example = "58") - private Long elapsedTime; + @Schema(description = "操作系统", example = "Windows 10") + private String os; + + /** + * 耗时(ms) + */ + @Schema(description = "耗时(ms)", example = "58") + private Long timeTaken; } diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/SystemLogResp.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/SystemLogResp.java index ccf6ce46..c0046436 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/SystemLogResp.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/model/resp/SystemLogResp.java @@ -54,16 +54,16 @@ public class SystemLogResp extends LogResp { private String requestUrl; /** - * 客户端IP + * IP */ - @Schema(description = "客户端IP", example = "192.168.0.1") - private String clientIp; + @Schema(description = "IP", example = "192.168.0.1") + private String ip; /** - * IP归属地 + * 地址 */ - @Schema(description = "IP归属地", example = "中国北京北京市") - private String location; + @Schema(description = "地址", example = "中国北京北京市") + private String address; /** * 浏览器 @@ -72,20 +72,8 @@ public class SystemLogResp extends LogResp { private String browser; /** - * 请求耗时(ms) + * 耗时(ms) */ - @Schema(description = "请求耗时(ms)", example = "58") - private Long elapsedTime; - - /** - * 错误信息 - */ - @Schema(description = "错误信息") - private String errorMsg; - - /** - * 异常详情 - */ - @Schema(description = "异常详情") - private String exceptionDetail; + @Schema(description = "耗时(ms)", example = "58") + private Long timeTaken; } diff --git a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/service/impl/LogServiceImpl.java b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/service/impl/LogServiceImpl.java index e0b96b59..6241716c 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/service/impl/LogServiceImpl.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/continew/admin/monitor/service/impl/LogServiceImpl.java @@ -23,8 +23,6 @@ import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import org.springframework.context.event.EventListener; -import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; @@ -63,27 +61,18 @@ public class LogServiceImpl implements LogService { private final LogMapper logMapper; private final CommonUserService commonUserService; - @Async - @EventListener - public void save(LogDO logDO) { - logMapper.insert(logDO); - } - @Override public PageDataResp page(OperationLogQuery query, PageQuery pageQuery) { QueryWrapper queryWrapper = QueryHelper.build(query); - // 限定查询信息 List fieldNameList = ReflectUtils.getNonStaticFieldsName(OperationLogResp.class); List columnNameList = fieldNameList.stream().filter(n -> !n.endsWith(SysConstants.DESCRIPTION_FIELD_SUFFIX)) .map(StrUtil::toUnderlineCase).collect(Collectors.toList()); queryWrapper.select(columnNameList); - // 分页查询 IPage page = logMapper.selectPage(pageQuery.toPage(), queryWrapper); PageDataResp pageDataResp = PageDataResp.build(page, OperationLogResp.class); - // 填充数据(如果是查询个人操作日志,只查询一次用户信息即可) if (null != query.getUid()) { String nickname = ExceptionUtils.exToNull(() -> commonUserService.getNicknameById(query.getUid())); @@ -98,18 +87,15 @@ public class LogServiceImpl implements LogService { public PageDataResp page(LoginLogQuery query, PageQuery pageQuery) { QueryWrapper queryWrapper = QueryHelper.build(query); queryWrapper.eq("module", "登录"); - // 限定查询信息 List fieldNameList = ReflectUtils.getNonStaticFieldsName(LoginLogResp.class); List columnNameList = fieldNameList.stream().filter(n -> !n.endsWith(SysConstants.DESCRIPTION_FIELD_SUFFIX)) .map(StrUtil::toUnderlineCase).collect(Collectors.toList()); queryWrapper.select(columnNameList); - // 分页查询 IPage page = logMapper.selectPage(pageQuery.toPage(), queryWrapper); PageDataResp pageDataResp = PageDataResp.build(page, LoginLogResp.class); - // 填充数据 pageDataResp.getList().forEach(this::fill); return pageDataResp; @@ -118,18 +104,15 @@ public class LogServiceImpl implements LogService { @Override public PageDataResp page(SystemLogQuery query, PageQuery pageQuery) { QueryWrapper queryWrapper = QueryHelper.build(query); - // 限定查询信息 List fieldNameList = ReflectUtils.getNonStaticFieldsName(SystemLogResp.class); List columnNameList = fieldNameList.stream().filter(n -> !n.endsWith(SysConstants.DESCRIPTION_FIELD_SUFFIX)) .map(StrUtil::toUnderlineCase).collect(Collectors.toList()); queryWrapper.select(columnNameList); - // 分页查询 IPage page = logMapper.selectPage(pageQuery.toPage(), queryWrapper); PageDataResp pageDataResp = PageDataResp.build(page, SystemLogResp.class); - // 填充数据 pageDataResp.getList().forEach(this::fill); return pageDataResp; diff --git a/continew-admin-system/src/main/java/top/charles7c/continew/admin/auth/model/resp/OnlineUserResp.java b/continew-admin-system/src/main/java/top/charles7c/continew/admin/auth/model/resp/OnlineUserResp.java index 384f9619..2c199412 100644 --- a/continew-admin-system/src/main/java/top/charles7c/continew/admin/auth/model/resp/OnlineUserResp.java +++ b/continew-admin-system/src/main/java/top/charles7c/continew/admin/auth/model/resp/OnlineUserResp.java @@ -66,13 +66,13 @@ public class OnlineUserResp implements Serializable { * 登录 IP */ @Schema(description = "登录 IP", example = "192.168.0.1") - private String clientIp; + private String ip; /** * 登录地点 */ @Schema(description = "登录地点", example = "中国北京北京市") - private String location; + private String address; /** * 浏览器 @@ -80,6 +80,12 @@ public class OnlineUserResp implements Serializable { @Schema(description = "浏览器", example = "Chrome 115.0.0.0") private String browser; + /** + * 操作系统 + */ + @Schema(description = "操作系统", example = "Windows 10") + private String os; + /** * 登录时间 */ diff --git a/continew-admin-ui/src/api/monitor/log.ts b/continew-admin-ui/src/api/monitor/log.ts index 8d764ce3..2a499d9b 100644 --- a/continew-admin-ui/src/api/monitor/log.ts +++ b/continew-admin-ui/src/api/monitor/log.ts @@ -5,9 +5,10 @@ const BASE_URL = '/monitor/log'; export interface LogRecord { id?: number; - clientIp: string; - location: string; + ip: string; + address: string; browser: string; + os: string; createTime: string; } @@ -22,7 +23,7 @@ export interface OperationLogRecord extends LogRecord { module: string; description: string; status: number; - errorMsg: string; + errorMsgString: string; createUserString: string; } @@ -30,8 +31,7 @@ export interface SystemLogRecord extends LogRecord { statusCode: number; requestMethod: string; requestUrl: string; - elapsedTime: number; - exceptionDetail?: string; + timeTaken: number; } export interface SystemLogDetailRecord extends SystemLogRecord { diff --git a/continew-admin-ui/src/api/monitor/online.ts b/continew-admin-ui/src/api/monitor/online.ts index 91699b68..da9f0617 100644 --- a/continew-admin-ui/src/api/monitor/online.ts +++ b/continew-admin-ui/src/api/monitor/online.ts @@ -7,9 +7,10 @@ export interface DataRecord { token: string; username: string; nickname: string; - clientIp: string; - location: string; + ip: string; + address: string; browser: string; + os: string; loginTime: string; } diff --git a/continew-admin-ui/src/views/monitor/log/login/index.vue b/continew-admin-ui/src/views/monitor/log/login/index.vue index 135869a8..db198a93 100644 --- a/continew-admin-ui/src/views/monitor/log/login/index.vue +++ b/continew-admin-ui/src/views/monitor/log/login/index.vue @@ -72,9 +72,10 @@ - - + + + diff --git a/continew-admin-ui/src/views/monitor/log/operation/index.vue b/continew-admin-ui/src/views/monitor/log/operation/index.vue index df9e27ae..161081cb 100644 --- a/continew-admin-ui/src/views/monitor/log/operation/index.vue +++ b/continew-admin-ui/src/views/monitor/log/operation/index.vue @@ -83,8 +83,8 @@ - - + + diff --git a/continew-admin-ui/src/views/monitor/log/system/index.vue b/continew-admin-ui/src/views/monitor/log/system/index.vue index b44340e4..bf042eeb 100644 --- a/continew-admin-ui/src/views/monitor/log/system/index.vue +++ b/continew-admin-ui/src/views/monitor/log/system/index.vue @@ -74,21 +74,21 @@ }} - - + + - + - + @@ -125,11 +116,11 @@ >
- + - {{ systemLog.clientIp }} + {{ systemLog.ip }} @@ -137,34 +128,40 @@ {{ systemLog.browser }} - + - {{ systemLog.location }} + {{ systemLog.address }} - + - - - {{ systemLog.elapsedTime }} ms - - - {{ systemLog.elapsedTime }} ms - - {{ systemLog.elapsedTime }} ms - + {{ systemLog.os }} - + {{ systemLog.createTime }} + + + + + + + {{ systemLog.timeTaken }} ms + + + {{ systemLog.timeTaken }} ms + + {{ systemLog.timeTaken }} ms + +
- - - -
{{ exceptionDetail }}
-
@@ -297,17 +280,16 @@ statusCode: 200, responseHeaders: '', responseBody: '', - elapsedTime: 0, - clientIp: '', - location: '', + timeTaken: 0, + ip: '', + address: '', browser: '', + os: '', createTime: '', }); const total = ref(0); - const exceptionDetail = ref(''); const loading = ref(false); const visible = ref(false); - const exceptionDetailVisible = ref(false); const data = reactive({ // 查询参数 @@ -362,24 +344,6 @@ visible.value = false; }; - /** - * 查看异常详情 - * - * @param record 记录信息 - */ - const toExceptionDetail = async (record: SystemLogRecord) => { - exceptionDetail.value = record.exceptionDetail || ''; - exceptionDetailVisible.value = true; - }; - - /** - * 关闭异常详情 - */ - const handleExceptionDetailCancel = () => { - exceptionDetail.value = ''; - exceptionDetailVisible.value = false; - }; - /** * 查询 */ diff --git a/continew-admin-ui/src/views/monitor/online/index.vue b/continew-admin-ui/src/views/monitor/online/index.vue index 6ba2b828..fac0244e 100644 --- a/continew-admin-ui/src/views/monitor/online/index.vue +++ b/continew-admin-ui/src/views/monitor/online/index.vue @@ -63,9 +63,10 @@ {{ record.nickname }}({{ record.username }})
- - + + + - - + +