From a0530dc3808b1146c8b2b9ef5a6f9cac8755bc9b Mon Sep 17 00:00:00 2001 From: "Ray.Hao" <1490493387@qq.com> Date: Wed, 26 Jun 2024 00:13:50 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E6=97=A5=E5=BF=97?= =?UTF-8?q?=E5=88=87=E9=9D=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../system/common/enums/DataScopeEnum.java | 7 +- .../system/common/enums/GenderEnum.java | 7 +- .../system/common/enums/LogTypeEnum.java | 28 +++++++ .../youlai/system/common/util/IPUtils.java | 81 +++++++++++++++++++ .../system/controller/AuthController.java | 4 + .../youlai/system/mapper/SysLogMapper.java | 2 +- .../youlai/system/model/entity/SysLog.java | 63 +++++++++------ .../syslog/annotation/LogAnnotation.java | 23 ++++++ .../plugin/syslog/aspect/LogAspect.java | 63 +++++++++++++++ .../youlai/system/service/SysLogService.java | 3 + .../service/impl/SysLogServiceImpl.java | 5 +- 11 files changed, 251 insertions(+), 35 deletions(-) create mode 100644 src/main/java/com/youlai/system/common/enums/LogTypeEnum.java create mode 100644 src/main/java/com/youlai/system/common/util/IPUtils.java create mode 100644 src/main/java/com/youlai/system/plugin/syslog/annotation/LogAnnotation.java create mode 100644 src/main/java/com/youlai/system/plugin/syslog/aspect/LogAspect.java diff --git a/src/main/java/com/youlai/system/common/enums/DataScopeEnum.java b/src/main/java/com/youlai/system/common/enums/DataScopeEnum.java index 019a881d..89ad9e37 100644 --- a/src/main/java/com/youlai/system/common/enums/DataScopeEnum.java +++ b/src/main/java/com/youlai/system/common/enums/DataScopeEnum.java @@ -9,6 +9,7 @@ import lombok.Getter; * @author haoxr * @since 2.3.0 */ +@Getter public enum DataScopeEnum implements IBaseEnum { /** @@ -19,11 +20,9 @@ public enum DataScopeEnum implements IBaseEnum { DEPT(2, "本部门数据"), SELF(3, "本人数据"); - @Getter - private Integer value; + private final Integer value; - @Getter - private String label; + private final String label; DataScopeEnum(Integer value, String label) { this.value = value; diff --git a/src/main/java/com/youlai/system/common/enums/GenderEnum.java b/src/main/java/com/youlai/system/common/enums/GenderEnum.java index a576ec5d..f239eea1 100644 --- a/src/main/java/com/youlai/system/common/enums/GenderEnum.java +++ b/src/main/java/com/youlai/system/common/enums/GenderEnum.java @@ -10,17 +10,16 @@ import lombok.Getter; * @author haoxr * @since 2022/10/14 */ +@Getter @Schema(enumAsRef = true) public enum GenderEnum implements IBaseEnum { MALE(1, "男"), FEMALE (2, "女"); - @Getter - private Integer value; + private final Integer value; - @Getter - private String label; + private final String label; GenderEnum(Integer value, String label) { this.value = value; diff --git a/src/main/java/com/youlai/system/common/enums/LogTypeEnum.java b/src/main/java/com/youlai/system/common/enums/LogTypeEnum.java new file mode 100644 index 00000000..f6731fbe --- /dev/null +++ b/src/main/java/com/youlai/system/common/enums/LogTypeEnum.java @@ -0,0 +1,28 @@ +package com.youlai.system.common.enums; + +import com.youlai.system.common.base.IBaseEnum; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Getter; + +/** + * 日志类型枚举 + * + * @author Ray + * @since 2.10.0 + */ +@Schema(enumAsRef = true) +@Getter +public enum LogTypeEnum implements IBaseEnum { + + OPERATION(1, "操作日志"), + LOGIN (2, "登录日志"); + + private final Integer value; + + private final String label; + + LogTypeEnum(Integer value, String label) { + this.value = value; + this.label = label; + } +} \ No newline at end of file diff --git a/src/main/java/com/youlai/system/common/util/IPUtils.java b/src/main/java/com/youlai/system/common/util/IPUtils.java new file mode 100644 index 00000000..ab65d7f9 --- /dev/null +++ b/src/main/java/com/youlai/system/common/util/IPUtils.java @@ -0,0 +1,81 @@ +package com.youlai.system.common.util; + +import cn.hutool.core.util.StrUtil; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; + +import java.net.InetAddress; +import java.net.UnknownHostException; + +/** + * IP工具类 + * + * @author Ray + * @since 2.10.0 + */ +@Slf4j +public class IPUtils { + + /** + * 获取IP地址 + * 使用Nginx等反向代理软件, 则不能通过request.getRemoteAddr()获取IP地址 + * 如果使用了多级反向代理的话,X-Forwarded-For的值并不止一个,而是一串IP地址,X-Forwarded-For中第一个非unknown的有效IP字符串,则为真实IP地址 + */ + public static String getIpAddr(HttpServletRequest request) { + String ip = null; + try { + if (request == null) { + return ""; + } + ip = request.getHeader("x-forwarded-for"); + if (checkIp(ip)) { + ip = request.getHeader("Proxy-Client-IP"); + } + if (checkIp(ip)) { + ip = request.getHeader("WL-Proxy-Client-IP"); + } + if (checkIp(ip)) { + ip = request.getHeader("HTTP_CLIENT_IP"); + } + if (checkIp(ip)) { + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + } + if (checkIp(ip)) { + ip = request.getRemoteAddr(); + if ("127.0.0.1".equals(ip) || "0:0:0:0:0:0:0:1".equals(ip)) { + // 根据网卡取本机配置的IP + ip = getLocalAddr(); + } + } + } catch (Exception e) { + log.error("IPUtils ERROR, {}", e.getMessage()); + } + + //使用代理,则获取第一个IP地址 + if (StrUtil.isNotBlank(ip) && ip.indexOf(",") > 0) { + ip = ip.substring(0, ip.indexOf(",")); + } + + return ip; + } + + + private static boolean checkIp(String ip) { + String unknown = "unknown"; + return StrUtil.isEmpty(ip) || ip.isEmpty() || unknown.equalsIgnoreCase(ip); + } + + /** + * 获取本机的IP地址 + */ + private static String getLocalAddr() { + try { + return InetAddress.getLocalHost().getHostAddress(); + } catch (UnknownHostException e) { + log.error("InetAddress.getLocalHost()-error, {}", e.getMessage()); + } + return null; + } + + +} diff --git a/src/main/java/com/youlai/system/controller/AuthController.java b/src/main/java/com/youlai/system/controller/AuthController.java index 7080fd93..e11cd86d 100644 --- a/src/main/java/com/youlai/system/controller/AuthController.java +++ b/src/main/java/com/youlai/system/controller/AuthController.java @@ -1,8 +1,10 @@ package com.youlai.system.controller; +import com.youlai.system.common.enums.LogTypeEnum; import com.youlai.system.common.result.Result; import com.youlai.system.model.dto.CaptchaResult; import com.youlai.system.model.dto.LoginResult; +import com.youlai.system.plugin.syslog.annotation.LogAnnotation; import com.youlai.system.service.AuthService; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.Parameter; @@ -28,6 +30,7 @@ public class AuthController { @Operation(summary = "登录") @PostMapping("/login") + @LogAnnotation(value = "登录", logType = LogTypeEnum.LOGIN) public Result login( @Parameter(description = "用户名", example = "admin") @RequestParam String username, @Parameter(description = "密码", example = "123456") @RequestParam String password @@ -38,6 +41,7 @@ public class AuthController { @Operation(summary = "注销") @DeleteMapping("/logout") + @LogAnnotation(value = "注销", logType = LogTypeEnum.LOGIN) public Result logout() { authService.logout(); return Result.success(); diff --git a/src/main/java/com/youlai/system/mapper/SysLogMapper.java b/src/main/java/com/youlai/system/mapper/SysLogMapper.java index b8186446..42cf220d 100644 --- a/src/main/java/com/youlai/system/mapper/SysLogMapper.java +++ b/src/main/java/com/youlai/system/mapper/SysLogMapper.java @@ -9,7 +9,7 @@ import org.apache.ibatis.annotations.Mapper; * 系统日志 数据库访问层 * * @author Ray - * @since 2.9.0 + * @since 2.10.0 */ @Mapper public interface SysLogMapper extends BaseMapper { diff --git a/src/main/java/com/youlai/system/model/entity/SysLog.java b/src/main/java/com/youlai/system/model/entity/SysLog.java index 831ffba1..a79095e3 100644 --- a/src/main/java/com/youlai/system/model/entity/SysLog.java +++ b/src/main/java/com/youlai/system/model/entity/SysLog.java @@ -1,18 +1,20 @@ package com.youlai.system.model.entity; -import com.baomidou.mybatisplus.annotation.IdType; -import com.baomidou.mybatisplus.annotation.TableField; -import com.baomidou.mybatisplus.annotation.TableId; -import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.annotation.*; + +import java.io.Serial; import java.io.Serializable; import java.util.Date; + +import com.youlai.system.common.base.BaseEntity; import lombok.Data; /** - * 系统日志 - * @TableName sys_log + * 系统日志 实体类 + * + * @author Ray + * @since 2.10.0 */ -@TableName(value ="sys_log") @Data public class SysLog implements Serializable { /** @@ -21,6 +23,34 @@ public class SysLog implements Serializable { @TableId(type = IdType.AUTO) private Long id; + /** + * 日志类型 + * + * @see com.youlai.system.common.enums.LogTypeEnum + */ + private Integer type; + + + /** + * 日志标题 + */ + private String title; + + /** + * 请求路径 + */ + private String requestUri; + + /** + * IP 地址 + */ + private String ip; + + /** + * 执行时间(毫秒) + */ + private Long executionTime; + /** * 创建人ID */ @@ -29,23 +59,6 @@ public class SysLog implements Serializable { /** * 创建时间 */ + @TableField(fill = FieldFill.INSERT) private Date createTime; - - /** - * 修改人ID - */ - private Long updateBy; - - /** - * 更新时间 - */ - private Date updateTime; - - /** - * 逻辑删除标识(1-已删除 0-未删除) - */ - private Integer isDeleted; - - @TableField(exist = false) - private static final long serialVersionUID = 1L; } \ No newline at end of file diff --git a/src/main/java/com/youlai/system/plugin/syslog/annotation/LogAnnotation.java b/src/main/java/com/youlai/system/plugin/syslog/annotation/LogAnnotation.java new file mode 100644 index 00000000..f7004724 --- /dev/null +++ b/src/main/java/com/youlai/system/plugin/syslog/annotation/LogAnnotation.java @@ -0,0 +1,23 @@ +package com.youlai.system.plugin.syslog.annotation; + +import com.youlai.system.common.enums.LogTypeEnum; + +import java.lang.annotation.*; + +/** + * 日志注解 + * + * @author Ray + * @since 2024/6/25 + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Documented +public @interface LogAnnotation { + + String value() default ""; + + LogTypeEnum logType() default LogTypeEnum.OPERATION; + + +} \ No newline at end of file diff --git a/src/main/java/com/youlai/system/plugin/syslog/aspect/LogAspect.java b/src/main/java/com/youlai/system/plugin/syslog/aspect/LogAspect.java new file mode 100644 index 00000000..7b17289e --- /dev/null +++ b/src/main/java/com/youlai/system/plugin/syslog/aspect/LogAspect.java @@ -0,0 +1,63 @@ +package com.youlai.system.plugin.syslog.aspect; + +import cn.hutool.core.date.DateUtil; +import cn.hutool.core.date.TimeInterval; +import cn.hutool.extra.servlet.ServletUtil; +import com.youlai.system.common.util.IPUtils; +import com.youlai.system.model.entity.SysLog; +import com.youlai.system.plugin.syslog.annotation.LogAnnotation; +import com.youlai.system.security.util.SecurityUtils; +import com.youlai.system.service.SysLogService; +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; +import org.aspectj.lang.ProceedingJoinPoint; +import org.aspectj.lang.annotation.Around; +import org.aspectj.lang.annotation.Aspect; +import org.aspectj.lang.annotation.Pointcut; +import org.springframework.stereotype.Component; + +/** + * 日志切面 + * + * @author Ray + * @since 2024/6/25 + */ +@Aspect +@Component +@RequiredArgsConstructor +public class LogAspect { + + private final SysLogService logService; + private final HttpServletRequest request; + + @Pointcut("@annotation(com.youlai.system.plugin.syslog.annotation.LogAnnotation)") + public void logPointcut() { + } + + @Around("logPointcut() && @annotation(logAnnotation)") + public Object logExecutionTime(ProceedingJoinPoint joinPoint, LogAnnotation logAnnotation) throws Throwable { + TimeInterval timer = DateUtil.timer(); + Object proceed = joinPoint.proceed(); + long executionTime =timer.interval(); + + // 创建日志对象 + SysLog log = new SysLog(); + log.setType(logAnnotation.logType().getValue()); + log.setTitle(logAnnotation.value()); + log.setRequestUri(request.getRequestURI()); + log.setIp(IPUtils.getIpAddr(request)); + log.setExecutionTime(executionTime); + log.setCreateBy(SecurityUtils.getUserId()); + + // 保存日志到数据库 + logService.save(log); + + return proceed; + } + + + + + + +} diff --git a/src/main/java/com/youlai/system/service/SysLogService.java b/src/main/java/com/youlai/system/service/SysLogService.java index f5127abe..616cc86a 100644 --- a/src/main/java/com/youlai/system/service/SysLogService.java +++ b/src/main/java/com/youlai/system/service/SysLogService.java @@ -4,7 +4,10 @@ import com.youlai.system.model.entity.SysLog; import com.baomidou.mybatisplus.extension.service.IService; /** + * 系统日志 服务接口 * + * @author Ray + * @since 2.10.0 */ public interface SysLogService extends IService { diff --git a/src/main/java/com/youlai/system/service/impl/SysLogServiceImpl.java b/src/main/java/com/youlai/system/service/impl/SysLogServiceImpl.java index d639fde3..24c7a444 100644 --- a/src/main/java/com/youlai/system/service/impl/SysLogServiceImpl.java +++ b/src/main/java/com/youlai/system/service/impl/SysLogServiceImpl.java @@ -7,11 +7,14 @@ import com.youlai.system.mapper.SysLogMapper; import org.springframework.stereotype.Service; /** + * 系统日志 服务实现类 * + * @author Ray + * @since 2.10.0 */ @Service public class SysLogServiceImpl extends ServiceImpl - implements SysLogService{ + implements SysLogService { }