diff --git a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/handler/GlobalExceptionHandler.java b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/handler/GlobalExceptionHandler.java index 5517c008..749a091d 100644 --- a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/handler/GlobalExceptionHandler.java +++ b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/handler/GlobalExceptionHandler.java @@ -41,7 +41,6 @@ import cn.hutool.core.util.StrUtil; import top.charles7c.cnadmin.common.exception.BadRequestException; import top.charles7c.cnadmin.common.exception.ServiceException; -import top.charles7c.cnadmin.common.model.dto.LogContext; import top.charles7c.cnadmin.common.model.vo.R; import top.charles7c.cnadmin.common.util.ExceptionUtils; import top.charles7c.cnadmin.common.util.StreamUtils; @@ -63,8 +62,8 @@ public class GlobalExceptionHandler { @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception.class) public R handleException(Exception e, HttpServletRequest request) { - this.setException(e); log.error("请求地址'{}',发生未知异常", request.getRequestURI(), e); + LogContextHolder.setException(e); return R.fail(e.getMessage()); } @@ -74,8 +73,8 @@ public class GlobalExceptionHandler { @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(RuntimeException.class) public R handleRuntimeException(RuntimeException e, HttpServletRequest request) { - this.setException(e); log.error("请求地址'{}',发生系统异常", request.getRequestURI(), e); + LogContextHolder.setException(e); return R.fail(e.getMessage()); } @@ -85,8 +84,8 @@ public class GlobalExceptionHandler { @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(ServiceException.class) public R handleServiceException(ServiceException e, HttpServletRequest request) { - this.setException(e); log.error("请求地址'{}',发生业务异常", request.getRequestURI(), e); + LogContextHolder.setErrorMsg(e.getMessage()); return R.fail(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()); } @@ -97,6 +96,7 @@ public class GlobalExceptionHandler { @ExceptionHandler(BadRequestException.class) public R handleBadRequestException(BadRequestException e, HttpServletRequest request) { log.error("请求地址'{}',自定义验证失败", request.getRequestURI(), e); + LogContextHolder.setErrorMsg(e.getMessage()); return R.fail(HttpStatus.BAD_REQUEST.value(), e.getMessage()); } @@ -107,8 +107,9 @@ public class GlobalExceptionHandler { @ExceptionHandler(BindException.class) public R handleBindException(BindException e, HttpServletRequest request) { log.error("请求地址'{}',参数验证失败", request.getRequestURI(), e); - String message = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ","); - return R.fail(HttpStatus.BAD_REQUEST.value(), message); + String errorMsg = StreamUtils.join(e.getAllErrors(), DefaultMessageSourceResolvable::getDefaultMessage, ","); + LogContextHolder.setErrorMsg(errorMsg); + return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } /** @@ -118,8 +119,9 @@ public class GlobalExceptionHandler { @ExceptionHandler(ConstraintViolationException.class) public R constraintViolationException(ConstraintViolationException e, HttpServletRequest request) { log.error("请求地址'{}',参数验证失败", request.getRequestURI(), e); - String message = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ","); - return R.fail(HttpStatus.BAD_REQUEST.value(), message); + String errorMsg = StreamUtils.join(e.getConstraintViolations(), ConstraintViolation::getMessage, ","); + LogContextHolder.setErrorMsg(errorMsg); + return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } /** @@ -129,8 +131,10 @@ public class GlobalExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public R handleMethodArgumentNotValidException(MethodArgumentNotValidException e, HttpServletRequest request) { log.error("请求地址'{}',参数验证失败", request.getRequestURI(), e); - return R.fail(HttpStatus.BAD_REQUEST.value(), ExceptionUtils - .exToNull(() -> Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage())); + String errorMsg = ExceptionUtils + .exToNull(() -> Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage()); + LogContextHolder.setErrorMsg(errorMsg); + return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } /** @@ -143,6 +147,7 @@ public class GlobalExceptionHandler { String subMsg = StrUtil.format("参数名:'{}',期望参数类型:'{}'", e.getName(), e.getParameter().getParameterType()); log.error("请求地址'{}',参数转换失败。方法:'{}',{}", request.getRequestURI(), Objects.requireNonNull(e.getParameter().getMethod()).getName(), subMsg, e); + LogContextHolder.setErrorMsg(subMsg); return R.fail(HttpStatus.BAD_REQUEST.value(), subMsg); } @@ -152,6 +157,7 @@ public class GlobalExceptionHandler { @ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED) @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()); } @@ -163,7 +169,9 @@ public class GlobalExceptionHandler { @ExceptionHandler(NotLoginException.class) public R handleNotLoginException(NotLoginException e, HttpServletRequest request) { log.error("请求地址'{}',认证失败,无法访问系统资源", request.getRequestURI(), e); - return R.fail(HttpStatus.UNAUTHORIZED.value(), "登录状态已过期,请重新登录"); + String errorMsg = "登录状态已过期,请重新登录"; + LogContextHolder.setErrorMsg(errorMsg); + return R.fail(HttpStatus.UNAUTHORIZED.value(), errorMsg); } /** @@ -172,22 +180,10 @@ public class GlobalExceptionHandler { @ResponseStatus(HttpStatus.BAD_REQUEST) @ExceptionHandler(MaxUploadSizeExceededException.class) public R handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e, HttpServletRequest request) { - String sizeLimit = StrUtil.subBetween(e.getMessage(), "The maximum size ", " for"); log.error("请求地址'{}',上传文件失败,文件大小超过限制", request.getRequestURI(), e); - return R.fail(HttpStatus.BAD_REQUEST.value(), - String.format("请上传小于 %s MB 的文件", NumberUtil.parseLong(sizeLimit) / 1024 / 1024)); - } - - /** - * 在系统日志上下文中保存异常信息 - * - * @param e - * 异常信息 - */ - private void setException(Exception e) { - LogContext logContext = LogContextHolder.get(); - if (logContext != null) { - logContext.setException(e); - } + String sizeLimit = StrUtil.subBetween(e.getMessage(), "The maximum size ", " for"); + String errorMsg = String.format("请上传小于 %s MB 的文件", NumberUtil.parseLong(sizeLimit) / 1024 / 1024); + LogContextHolder.setErrorMsg(errorMsg); + return R.fail(HttpStatus.BAD_REQUEST.value(), errorMsg); } } \ No newline at end of file diff --git a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/model/dto/LogContext.java b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/model/dto/LogContext.java index cd30f8fd..0145ca00 100644 --- a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/model/dto/LogContext.java +++ b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/model/dto/LogContext.java @@ -40,7 +40,12 @@ public class LogContext { private LocalDateTime createTime; /** - * 异常 + * 错误信息 + */ + private String errorMsg; + + /** + * 异常信息 */ private Exception exception; } diff --git a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/util/holder/LogContextHolder.java b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/util/holder/LogContextHolder.java index 6a13d012..d01ec3f4 100644 --- a/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/util/holder/LogContextHolder.java +++ b/continew-admin-common/src/main/java/top/charles7c/cnadmin/common/util/holder/LogContextHolder.java @@ -57,4 +57,31 @@ public class LogContextHolder { public static void remove() { LOG_THREAD_LOCAL.remove(); } + + /** + * 在系统日志上下文中保存异常信息 + * + * @param e + * 异常信息 + */ + public static void setException(Exception e) { + LogContext logContext = get(); + if (logContext != null) { + logContext.setErrorMsg(e.getMessage()); + logContext.setException(e); + } + } + + /** + * 在系统日志上下文中保存错误信息(非未知异常不记录异常信息,只记录错误信息) + * + * @param errorMsg + * 错误信息 + */ + public static void setErrorMsg(String errorMsg) { + LogContext logContext = get(); + if (logContext != null) { + logContext.setErrorMsg(errorMsg); + } + } } diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/interceptor/LogInterceptor.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/interceptor/LogInterceptor.java index c5fd5c54..250629a0 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/interceptor/LogInterceptor.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/interceptor/LogInterceptor.java @@ -110,7 +110,7 @@ public class LogInterceptor implements HandlerInterceptor { } /** - * 记录请求耗时及异常信息 + * 记录请求耗时及异常详情 * * @return 系统日志信息 */ @@ -123,11 +123,17 @@ public class LogInterceptor implements HandlerInterceptor { sysLog.setElapsedTime(System.currentTimeMillis() - LocalDateTimeUtil.toEpochMilli(sysLog.getCreateTime())); sysLog.setStatus(LogStatusEnum.SUCCESS); - // 记录异常信息 + // 记录错误信息(非未知异常不记录异常详情,只记录错误信息) + String errorMsg = logContext.getErrorMsg(); + if (StrUtil.isNotBlank(errorMsg)) { + sysLog.setStatus(LogStatusEnum.FAILURE); + sysLog.setErrorMsg(errorMsg); + } + // 记录异常详情 Exception exception = logContext.getException(); if (exception != null) { sysLog.setStatus(LogStatusEnum.FAILURE); - sysLog.setException(ExceptionUtil.stacktraceToString(exception, -1)); + sysLog.setExceptionDetail(ExceptionUtil.stacktraceToString(exception, -1)); } return sysLog; } diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/entity/SysLog.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/entity/SysLog.java index 03f70f16..a1c62c02 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/entity/SysLog.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/entity/SysLog.java @@ -110,9 +110,14 @@ public class SysLog implements Serializable { private String browser; /** - * 异常 + * 错误信息 */ - private String exception; + private String errorMsg; + + /** + * 异常详情 + */ + private String exceptionDetail; /** * 创建人 diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/query/LoginLogQuery.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/query/LoginLogQuery.java new file mode 100644 index 00000000..26ff2998 --- /dev/null +++ b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/query/LoginLogQuery.java @@ -0,0 +1,59 @@ +/* + * 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.cnadmin.monitor.model.query; + +import java.io.Serializable; +import java.util.Date; +import java.util.List; + +import lombok.Data; + +import io.swagger.v3.oas.annotations.media.Schema; + +import org.springdoc.api.annotations.ParameterObject; +import org.springframework.format.annotation.DateTimeFormat; + +import top.charles7c.cnadmin.common.annotation.Query; + +/** + * 登录日志查询条件 + * + * @author Charles7c + * @since 2023/1/16 23:25 + */ +@Data +@ParameterObject +@Schema(description = "登录日志查询条件") +public class LoginLogQuery implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 登录状态(1成功 2失败) + */ + @Schema(description = "登录状态(1成功 2失败)") + @Query(type = Query.Type.EQUAL) + private Integer status; + + /** + * 登录时间 + */ + @Schema(description = "登录时间") + @Query(type = Query.Type.BETWEEN) + @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") + private List createTime; +} diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/OperationLogService.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/LogVO.java similarity index 51% rename from continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/OperationLogService.java rename to continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/LogVO.java index 222a096f..0388bb59 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/OperationLogService.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/LogVO.java @@ -14,29 +14,32 @@ * limitations under the License. */ -package top.charles7c.cnadmin.monitor.service; +package top.charles7c.cnadmin.monitor.model.vo; -import top.charles7c.cnadmin.common.model.query.PageQuery; -import top.charles7c.cnadmin.common.model.vo.PageInfo; -import top.charles7c.cnadmin.monitor.model.query.OperationLogQuery; -import top.charles7c.cnadmin.monitor.model.vo.OperationLogVO; +import lombok.Data; + +import io.swagger.v3.oas.annotations.media.Schema; + +import com.fasterxml.jackson.annotation.JsonIgnore; /** - * 操作日志业务接口 + * 基础日志信息 * * @author Charles7c - * @since 2023/1/15 21:05 + * @since 2023/1/17 21:43 */ -public interface OperationLogService { +@Data +public class LogVO { /** - * 分页查询列表 - * - * @param query - * 查询条件 - * @param pageQuery - * 分页查询条件 - * @return 分页信息 + * 创建人 */ - PageInfo list(OperationLogQuery query, PageQuery pageQuery); + @JsonIgnore + private Long createUser; + + /** + * 创建人 + */ + @Schema(description = "创建人") + private String createUserString; } diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/LoginLogVO.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/LoginLogVO.java new file mode 100644 index 00000000..afbab97a --- /dev/null +++ b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/LoginLogVO.java @@ -0,0 +1,87 @@ +/* + * 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.cnadmin.monitor.model.vo; + +import java.io.Serializable; +import java.time.LocalDateTime; + +import lombok.Data; + +import io.swagger.v3.oas.annotations.media.Schema; + +import top.charles7c.cnadmin.monitor.enums.LogStatusEnum; + +/** + * 登录日志信息 + * + * @author Charles7c + * @since 2023/1/16 23:19 + */ +@Data +@Schema(description = "登录日志信息") +public class LoginLogVO extends LogVO implements Serializable { + + private static final long serialVersionUID = 1L; + + /** + * 日志ID + */ + @Schema(description = "日志ID") + private Long logId; + + /** + * 日志描述 + */ + @Schema(description = "日志描述") + private String description; + + /** + * 操作状态(1成功 2失败) + */ + @Schema(description = "操作状态(1成功 2失败)", type = "Integer", allowableValues = {"1", "2"}) + private LogStatusEnum status; + + /** + * 登录IP + */ + @Schema(description = "登录IP") + private String clientIp; + + /** + * 登录地点 + */ + @Schema(description = "登录地点") + private String location; + + /** + * 浏览器 + */ + @Schema(description = "浏览器") + private String browser; + + /** + * 错误信息 + */ + @Schema(description = "错误信息") + private String errorMsg; + + /** + * 登录时间 + */ + @Schema(description = "登录时间") + private LocalDateTime createTime; +} diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/OperationLogVO.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/OperationLogVO.java index 7f9ca815..6b8f8719 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/OperationLogVO.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/model/vo/OperationLogVO.java @@ -23,8 +23,6 @@ import lombok.Data; import io.swagger.v3.oas.annotations.media.Schema; -import com.fasterxml.jackson.annotation.JsonIgnore; - import top.charles7c.cnadmin.monitor.enums.LogStatusEnum; /** @@ -35,7 +33,7 @@ import top.charles7c.cnadmin.monitor.enums.LogStatusEnum; */ @Data @Schema(description = "操作日志信息") -public class OperationLogVO implements Serializable { +public class OperationLogVO extends LogVO implements Serializable { private static final long serialVersionUID = 1L; @@ -76,16 +74,10 @@ public class OperationLogVO implements Serializable { private String browser; /** - * 操作人 + * 错误信息 */ - @JsonIgnore - private Long createUser; - - /** - * 操作人 - */ - @Schema(description = "操作人") - private String createUserString; + @Schema(description = "错误信息") + private String errorMsg; /** * 操作时间 diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/LogService.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/LogService.java index 834508b7..02638e55 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/LogService.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/LogService.java @@ -16,6 +16,13 @@ package top.charles7c.cnadmin.monitor.service; +import top.charles7c.cnadmin.common.model.query.PageQuery; +import top.charles7c.cnadmin.common.model.vo.PageInfo; +import top.charles7c.cnadmin.monitor.model.query.LoginLogQuery; +import top.charles7c.cnadmin.monitor.model.query.OperationLogQuery; +import top.charles7c.cnadmin.monitor.model.vo.LoginLogVO; +import top.charles7c.cnadmin.monitor.model.vo.OperationLogVO; + /** * 系统日志业务接口 * @@ -24,4 +31,25 @@ package top.charles7c.cnadmin.monitor.service; */ public interface LogService { + /** + * 分页查询操作日志列表 + * + * @param query + * 查询条件 + * @param pageQuery + * 分页查询条件 + * @return 操作日志分页信息 + */ + PageInfo list(OperationLogQuery query, PageQuery pageQuery); + + /** + * 分页查询登录日志列表 + * + * @param query + * 查询条件 + * @param pageQuery + * 分页查询条件 + * @return 登录日志分页信息 + */ + PageInfo list(LoginLogQuery query, PageQuery pageQuery); } diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/impl/LogServiceImpl.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/impl/LogServiceImpl.java index 059aa4c2..936018b5 100644 --- a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/impl/LogServiceImpl.java +++ b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/impl/LogServiceImpl.java @@ -16,6 +16,10 @@ package top.charles7c.cnadmin.monitor.service.impl; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -23,9 +27,25 @@ 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; +import com.baomidou.mybatisplus.core.metadata.IPage; + +import cn.hutool.core.util.StrUtil; + +import top.charles7c.cnadmin.common.model.query.PageQuery; +import top.charles7c.cnadmin.common.model.vo.PageInfo; +import top.charles7c.cnadmin.common.util.ExceptionUtils; +import top.charles7c.cnadmin.common.util.ReflectUtils; +import top.charles7c.cnadmin.common.util.helper.QueryHelper; import top.charles7c.cnadmin.monitor.mapper.LogMapper; import top.charles7c.cnadmin.monitor.model.entity.SysLog; +import top.charles7c.cnadmin.monitor.model.query.LoginLogQuery; +import top.charles7c.cnadmin.monitor.model.query.OperationLogQuery; +import top.charles7c.cnadmin.monitor.model.vo.LogVO; +import top.charles7c.cnadmin.monitor.model.vo.LoginLogVO; +import top.charles7c.cnadmin.monitor.model.vo.OperationLogVO; import top.charles7c.cnadmin.monitor.service.LogService; +import top.charles7c.cnadmin.system.service.UserService; /** * 系统日志业务实现类 @@ -39,10 +59,69 @@ import top.charles7c.cnadmin.monitor.service.LogService; public class LogServiceImpl implements LogService { private final LogMapper logMapper; + private final UserService userService; @Async @EventListener public void save(SysLog sysLog) { logMapper.insert(sysLog); } + + @Override + public PageInfo list(OperationLogQuery query, PageQuery pageQuery) { + QueryWrapper queryWrapper = QueryHelper.build(query); + + // 限定查询信息 + String[] fieldsName = ReflectUtils.getNonStaticFieldsName(OperationLogVO.class); + List columns = Arrays.stream(fieldsName).map(StrUtil::toUnderlineCase) + .filter(n -> !n.endsWith("string")).collect(Collectors.toList()); + queryWrapper.select(columns); + + // 分页查询 + IPage page = logMapper.selectPage(pageQuery.toPage(), queryWrapper); + PageInfo pageInfo = PageInfo.build(page, OperationLogVO.class); + + // 填充数据(如果是查询个人操作日志,只查询一次用户信息即可) + if (query.getUid() != null) { + String nickname = ExceptionUtils.exToNull(() -> userService.getById(query.getUid()).getNickname()); + pageInfo.getList().forEach(o -> o.setCreateUserString(nickname)); + } else { + pageInfo.getList().forEach(this::fill); + } + return pageInfo; + } + + @Override + public PageInfo list(LoginLogQuery query, PageQuery pageQuery) { + QueryWrapper queryWrapper = QueryHelper.build(query); + queryWrapper.and(qw -> qw.like("request_url", "/auth/login").or().like("request_url", "/auth/logout")); + + // 限定查询信息 + String[] fieldsName = ReflectUtils.getNonStaticFieldsName(LoginLogVO.class); + List columns = Arrays.stream(fieldsName).map(StrUtil::toUnderlineCase) + .filter(n -> !n.endsWith("string")).collect(Collectors.toList()); + queryWrapper.select(columns); + + // 分页查询 + IPage page = logMapper.selectPage(pageQuery.toPage(), queryWrapper); + PageInfo pageInfo = PageInfo.build(page, LoginLogVO.class); + + // 填充数据 + pageInfo.getList().forEach(this::fill); + return pageInfo; + } + + /** + * 填充数据 + * + * @param vo + * VO + */ + private void fill(LogVO vo) { + Long createUser = vo.getCreateUser(); + if (createUser == null) { + return; + } + vo.setCreateUserString(ExceptionUtils.exToNull(() -> userService.getById(vo.getCreateUser())).getNickname()); + } } diff --git a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/impl/OperationLogServiceImpl.java b/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/impl/OperationLogServiceImpl.java deleted file mode 100644 index da61bb53..00000000 --- a/continew-admin-monitor/src/main/java/top/charles7c/cnadmin/monitor/service/impl/OperationLogServiceImpl.java +++ /dev/null @@ -1,97 +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.cnadmin.monitor.service.impl; - -import java.util.Arrays; -import java.util.List; -import java.util.stream.Collectors; - -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; - -import org.springframework.stereotype.Service; - -import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; -import com.baomidou.mybatisplus.core.metadata.IPage; - -import cn.hutool.core.util.StrUtil; - -import top.charles7c.cnadmin.common.model.query.PageQuery; -import top.charles7c.cnadmin.common.model.vo.PageInfo; -import top.charles7c.cnadmin.common.util.ReflectUtils; -import top.charles7c.cnadmin.common.util.helper.QueryHelper; -import top.charles7c.cnadmin.monitor.mapper.LogMapper; -import top.charles7c.cnadmin.monitor.model.entity.SysLog; -import top.charles7c.cnadmin.monitor.model.query.OperationLogQuery; -import top.charles7c.cnadmin.monitor.model.vo.OperationLogVO; -import top.charles7c.cnadmin.monitor.service.OperationLogService; -import top.charles7c.cnadmin.system.mapper.UserMapper; -import top.charles7c.cnadmin.system.model.entity.SysUser; - -/** - * 操作日志业务实现类 - * - * @author Charles7c - * @since 2023/1/15 21:05 - */ -@Slf4j -@Service -@RequiredArgsConstructor -public class OperationLogServiceImpl implements OperationLogService { - - private final LogMapper logMapper; - private final UserMapper userMapper; - - @Override - public PageInfo list(OperationLogQuery query, PageQuery pageQuery) { - QueryWrapper queryWrapper = QueryHelper.build(query); - - // 限定查询信息 - String[] fieldsName = ReflectUtils.getNonStaticFieldsName(OperationLogVO.class); - List columns = Arrays.stream(fieldsName).map(StrUtil::toUnderlineCase) - .filter(n -> !n.endsWith("string")).collect(Collectors.toList()); - queryWrapper.select(columns); - - // 分页查询 - IPage page = logMapper.selectPage(pageQuery.toPage(), queryWrapper); - PageInfo pageInfo = PageInfo.build(page, OperationLogVO.class); - - // 填充数据(如果是查询个人操作日志,只查询一次用户信息即可) - if (query.getUid() != null) { - SysUser sysUser = userMapper.selectById(query.getUid()); - pageInfo.getList().forEach(o -> o.setCreateUserString(sysUser.getUsername())); - } else { - pageInfo.getList().forEach(this::fill); - } - return pageInfo; - } - - /** - * 填充数据 - * - * @param vo - * VO - */ - private void fill(OperationLogVO vo) { - Long createUser = vo.getCreateUser(); - if (createUser == null) { - return; - } - SysUser sysUser = userMapper.selectById(createUser); - vo.setCreateUserString(sysUser.getUsername()); - } -} diff --git a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/UserService.java b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/UserService.java index 35062b6a..ddb080ff 100644 --- a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/UserService.java +++ b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/UserService.java @@ -79,4 +79,13 @@ public interface UserService { * 用户ID */ void updateEmail(String newEmail, String currentPassword, Long userId); + + /** + * 根据 ID 查询 + * + * @param userId + * 用户ID + * @return 用户信息 + */ + SysUser getById(Long userId); } diff --git a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/impl/UserServiceImpl.java b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/impl/UserServiceImpl.java index 1600a032..b9fc9644 100644 --- a/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/impl/UserServiceImpl.java +++ b/continew-admin-system/src/main/java/top/charles7c/cnadmin/system/service/impl/UserServiceImpl.java @@ -141,14 +141,8 @@ public class UserServiceImpl implements UserService { LoginHelper.updateLoginUser(loginUser); } - /** - * 根据 ID 查询 - * - * @param userId - * 用户 ID - * @return 用户信息 - */ - private SysUser getById(Long userId) { + @Override + public SysUser getById(Long userId) { ValidationUtils.exIfNull(userId, "用户不存在"); SysUser sysUser = userMapper.selectById(userId); ValidationUtils.exIfNull(sysUser, String.format("ID为 [%s] 的用户已不存在", userId)); diff --git a/continew-admin-ui/src/api/monitor/login-log.ts b/continew-admin-ui/src/api/monitor/login-log.ts new file mode 100644 index 00000000..e27db04d --- /dev/null +++ b/continew-admin-ui/src/api/monitor/login-log.ts @@ -0,0 +1,33 @@ +import axios from 'axios'; +import qs from 'query-string'; + +export interface LoginLogRecord { + logId: string; + status: number; + clientIp: string; + location: string; + browser: string; + errorMsg: string; + createUserString: string; + createTime: string; +} + +export interface LoginLogParams extends Partial { + page: number; + size: number; + sort: Array; +} + +export interface LoginLogListRes { + list: LoginLogRecord[]; + total: number; +} + +export function queryLoginLogList(params: LoginLogParams) { + return axios.get('/monitor/log/login', { + params, + paramsSerializer: (obj) => { + return qs.stringify(obj); + }, + }); +} \ No newline at end of file diff --git a/continew-admin-ui/src/api/monitor/operation-log.ts b/continew-admin-ui/src/api/monitor/operation-log.ts index 48b9d482..06d4ea70 100644 --- a/continew-admin-ui/src/api/monitor/operation-log.ts +++ b/continew-admin-ui/src/api/monitor/operation-log.ts @@ -4,10 +4,11 @@ import qs from 'query-string'; export interface OperationLogRecord { logId: string; description: string; - status: number, - clientIp: string, - location: string, - browser: string, + status: number; + clientIp: string; + location: string; + browser: string; + errorMsg: string; createUserString: string; createTime: string; } diff --git a/continew-admin-ui/src/locale/en-US.ts b/continew-admin-ui/src/locale/en-US.ts index cd129d69..cd2ee1cf 100644 --- a/continew-admin-ui/src/locale/en-US.ts +++ b/continew-admin-ui/src/locale/en-US.ts @@ -8,7 +8,8 @@ import localeMonitor from '@/views/dashboard/monitor/locale/en-US'; import localeDataAnalysis from '@/views/visualization/data-analysis/locale/en-US'; import localeMultiDAnalysis from '@/views/visualization/multi-dimension-data-analysis/locale/en-US'; -import localeLog from '@/views/monitor/log/operation/locale/en-US'; +import localeOperationLog from '@/views/monitor/log/operation/locale/en-US'; +import localeLoginLog from '@/views/monitor/log/login/locale/en-US'; import localeSearchTable from '@/views/list/search-table/locale/en-US'; import localeCardList from '@/views/list/card/locale/en-US'; @@ -55,7 +56,8 @@ export default { ...localeDataAnalysis, ...localeMultiDAnalysis, - ...localeLog, + ...localeOperationLog, + ...localeLoginLog, ...localeSearchTable, ...localeCardList, diff --git a/continew-admin-ui/src/locale/zh-CN.ts b/continew-admin-ui/src/locale/zh-CN.ts index 1fbc21cd..baad96d6 100644 --- a/continew-admin-ui/src/locale/zh-CN.ts +++ b/continew-admin-ui/src/locale/zh-CN.ts @@ -8,7 +8,8 @@ import localeMonitor from '@/views/dashboard/monitor/locale/zh-CN'; import localeDataAnalysis from '@/views/visualization/data-analysis/locale/zh-CN'; import localeMultiDAnalysis from '@/views/visualization/multi-dimension-data-analysis/locale/zh-CN'; -import localeLog from '@/views/monitor/log/operation/locale/zh-CN'; +import localeOperationLog from '@/views/monitor/log/operation/locale/zh-CN'; +import localeLoginLog from '@/views/monitor/log/login/locale/zh-CN'; import localeSearchTable from '@/views/list/search-table/locale/zh-CN'; import localeCardList from '@/views/list/card/locale/zh-CN'; @@ -55,7 +56,8 @@ export default { ...localeDataAnalysis, ...localeMultiDAnalysis, - ...localeLog, + ...localeOperationLog, + ...localeLoginLog, ...localeSearchTable, ...localeCardList, diff --git a/continew-admin-ui/src/router/routes/modules/monitor.ts b/continew-admin-ui/src/router/routes/modules/monitor.ts index efd2e4bf..186ed436 100644 --- a/continew-admin-ui/src/router/routes/modules/monitor.ts +++ b/continew-admin-ui/src/router/routes/modules/monitor.ts @@ -22,6 +22,16 @@ const Monitor: AppRouteRecordRaw = { roles: ['*'], }, }, + { + path: 'log/login', + name: 'LoginLog', + component: () => import('@/views/monitor/log/login/index.vue'), + meta: { + locale: 'menu.log.login.list', + requiresAuth: true, + roles: ['*'], + }, + }, ], }; diff --git a/continew-admin-ui/src/router/routes/modules/user.ts b/continew-admin-ui/src/router/routes/modules/user.ts index c57a2613..eb6b3a4e 100644 --- a/continew-admin-ui/src/router/routes/modules/user.ts +++ b/continew-admin-ui/src/router/routes/modules/user.ts @@ -2,7 +2,7 @@ import { DEFAULT_LAYOUT } from '../base'; import { AppRouteRecordRaw } from '../types'; const USER: AppRouteRecordRaw = { - path: '/system/user', + path: '/login/user', name: 'user', component: DEFAULT_LAYOUT, meta: { diff --git a/continew-admin-ui/src/views/monitor/log/login/index.vue b/continew-admin-ui/src/views/monitor/log/login/index.vue new file mode 100644 index 00000000..8b4bb1ae --- /dev/null +++ b/continew-admin-ui/src/views/monitor/log/login/index.vue @@ -0,0 +1,214 @@ + + + + + + + diff --git a/continew-admin-ui/src/views/monitor/log/login/locale/en-US.ts b/continew-admin-ui/src/views/monitor/log/login/locale/en-US.ts new file mode 100644 index 00000000..f976d791 --- /dev/null +++ b/continew-admin-ui/src/views/monitor/log/login/locale/en-US.ts @@ -0,0 +1,3 @@ +export default { + 'menu.log.login.list': 'Login log', +}; diff --git a/continew-admin-ui/src/views/monitor/log/login/locale/zh-CN.ts b/continew-admin-ui/src/views/monitor/log/login/locale/zh-CN.ts new file mode 100644 index 00000000..c036115f --- /dev/null +++ b/continew-admin-ui/src/views/monitor/log/login/locale/zh-CN.ts @@ -0,0 +1,3 @@ +export default { + 'menu.log.login.list': '登录日志', +}; 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 00cfa0dd..778351a7 100644 --- a/continew-admin-ui/src/views/monitor/log/operation/index.vue +++ b/continew-admin-ui/src/views/monitor/log/operation/index.vue @@ -81,10 +81,12 @@ - - - 失败 - + + + + 失败 + + diff --git a/continew-admin-ui/src/views/system/user/center/components/operation-log.vue b/continew-admin-ui/src/views/system/user/center/components/operation-log.vue index c8d23ca1..6da32340 100644 --- a/continew-admin-ui/src/views/system/user/center/components/operation-log.vue +++ b/continew-admin-ui/src/views/system/user/center/components/operation-log.vue @@ -22,10 +22,12 @@ - - - 失败 - + + + + 失败 + +