feat: 添加日志切面
This commit is contained in:
@@ -9,6 +9,7 @@ import lombok.Getter;
|
||||
* @author haoxr
|
||||
* @since 2.3.0
|
||||
*/
|
||||
@Getter
|
||||
public enum DataScopeEnum implements IBaseEnum<Integer> {
|
||||
|
||||
/**
|
||||
@@ -19,11 +20,9 @@ public enum DataScopeEnum implements IBaseEnum<Integer> {
|
||||
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;
|
||||
|
||||
@@ -10,17 +10,16 @@ import lombok.Getter;
|
||||
* @author haoxr
|
||||
* @since 2022/10/14
|
||||
*/
|
||||
@Getter
|
||||
@Schema(enumAsRef = true)
|
||||
public enum GenderEnum implements IBaseEnum<Integer> {
|
||||
|
||||
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;
|
||||
|
||||
@@ -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<Integer> {
|
||||
|
||||
OPERATION(1, "操作日志"),
|
||||
LOGIN (2, "登录日志");
|
||||
|
||||
private final Integer value;
|
||||
|
||||
private final String label;
|
||||
|
||||
LogTypeEnum(Integer value, String label) {
|
||||
this.value = value;
|
||||
this.label = label;
|
||||
}
|
||||
}
|
||||
81
src/main/java/com/youlai/system/common/util/IPUtils.java
Normal file
81
src/main/java/com/youlai/system/common/util/IPUtils.java
Normal file
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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<LoginResult> 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();
|
||||
|
||||
@@ -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<SysLog> {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -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<SysLog> {
|
||||
|
||||
|
||||
@@ -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<SysLogMapper, SysLog>
|
||||
implements SysLogService{
|
||||
implements SysLogService {
|
||||
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user