🎨 操作日志功能:生产日志部分
This commit is contained in:
parent
7dbe420d8d
commit
20e65bf2f7
|
@ -85,6 +85,22 @@
|
|||
<artifactId>fastjson</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-webmvc</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>servlet-api</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
package cn.iocoder.mall.system.biz.log.operation.annotation;
|
||||
|
||||
import java.lang.annotation.*;
|
||||
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/10/15 18:09
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Documented
|
||||
public @interface OperationLogging {
|
||||
|
||||
/**
|
||||
* 日志信息
|
||||
* @return
|
||||
*/
|
||||
String value();
|
||||
}
|
|
@ -0,0 +1,118 @@
|
|||
package cn.iocoder.mall.system.biz.log.operation.aspect;
|
||||
|
||||
import cn.hutool.core.util.ArrayUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import cn.iocoder.common.framework.util.HttpUtil;
|
||||
import cn.iocoder.common.framework.util.MallUtil;
|
||||
import cn.iocoder.mall.system.biz.log.operation.annotation.OperationLogging;
|
||||
import cn.iocoder.mall.system.biz.log.operation.enums.LogStatus;
|
||||
import cn.iocoder.mall.system.biz.log.operation.event.OperationLogEvent;
|
||||
import cn.iocoder.mall.system.biz.log.operation.model.dto.OperationLogDTO;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.Signature;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/10/15 18:16
|
||||
*/
|
||||
@Slf4j
|
||||
@Aspect
|
||||
@Order(0)
|
||||
@RequiredArgsConstructor
|
||||
public class OperationLogAspect {
|
||||
private final ApplicationEventPublisher publisher;
|
||||
|
||||
@Around("@annotation(operationLogging)")
|
||||
public Object around(ProceedingJoinPoint joinPoint, OperationLogging operationLogging) throws Throwable {
|
||||
Signature signature = joinPoint.getSignature();
|
||||
String strClassName = joinPoint.getTarget().getClass().getName();
|
||||
String strMethodName = signature.getName();
|
||||
log.debug("[类名]:{},[方法]:{}", strClassName, strMethodName);
|
||||
|
||||
// 获取日志
|
||||
OperationLogDTO operationLogDTO = prodOperationLog();
|
||||
operationLogDTO.setMsg(operationLogging.value());
|
||||
// 记录参数
|
||||
MethodSignature methodSignature = (MethodSignature) signature;
|
||||
operationLogDTO.setParams(getParams(joinPoint, methodSignature));
|
||||
// 开始时间
|
||||
long startTime = System.currentTimeMillis();
|
||||
Object result;
|
||||
try {
|
||||
result = joinPoint.proceed();
|
||||
} catch (Throwable throwable) {
|
||||
operationLogDTO.setStatus(LogStatus.FAIL.getValue());
|
||||
throw throwable;
|
||||
}
|
||||
// 结束时间
|
||||
operationLogDTO.setResponseTime((int) (System.currentTimeMillis() - startTime));
|
||||
// 发布事件
|
||||
publisher.publishEvent(new OperationLogEvent(operationLogDTO));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取方法参数
|
||||
* @param joinPoint joinPoint
|
||||
* @param methodSignature 方法签名
|
||||
* @return 方法参数的Json字符串形式
|
||||
*/
|
||||
private String getParams(ProceedingJoinPoint joinPoint, MethodSignature methodSignature) {
|
||||
String[] parameterNames = methodSignature.getParameterNames();
|
||||
Object[] args = joinPoint.getArgs();
|
||||
if(ArrayUtil.isEmpty(parameterNames)){
|
||||
return null;
|
||||
}
|
||||
Map<String, Object> paramsMap = new HashMap<>();
|
||||
for (int i = 0; i < parameterNames.length; i++) {
|
||||
paramsMap.put(parameterNames[i], args[i]);
|
||||
}
|
||||
return JSONUtil.toJsonStr(paramsMap);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据请求生成操作日志
|
||||
* @return 操作日志DTO
|
||||
*/
|
||||
private OperationLogDTO prodOperationLog() {
|
||||
HttpServletRequest request = ((ServletRequestAttributes) Objects
|
||||
.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
|
||||
|
||||
return new OperationLogDTO()
|
||||
.setTraceId(MallUtil.getTraceId())
|
||||
.setUri(URLUtil.getPath(request.getRequestURI()))
|
||||
.setUserAgent(HttpUtil.getUserAgent(request))
|
||||
.setIp(HttpUtil.getIp(request))
|
||||
.setMethod(request.getMethod())
|
||||
// TODO 获取管理员用户名 或者 用户ID
|
||||
// .setOperator(Objects.requireNonNull(LogUtils.getUsername()))
|
||||
.setStatus(LogStatus.SUCCESS.getValue());
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package cn.iocoder.mall.system.biz.log.operation.enums;
|
||||
|
||||
/**
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2020/5/15 14:47
|
||||
*/
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* 操作状态
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum LogStatus {
|
||||
/**
|
||||
* 成功
|
||||
*/
|
||||
SUCCESS(1),
|
||||
/**
|
||||
* 失败
|
||||
*/
|
||||
FAIL(0);
|
||||
|
||||
private final int value;
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
package cn.iocoder.mall.system.biz.log.operation.event;
|
||||
|
||||
import cn.iocoder.mall.system.biz.log.operation.model.dto.OperationLogDTO;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* @author
|
||||
* 系统日志事件
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public class OperationLogEvent {
|
||||
private final OperationLogDTO operationLogDTO;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cn.iocoder.mall.system.biz.log.operation.event;
|
||||
|
||||
import cn.iocoder.mall.system.biz.log.operation.service.OperationLogSaveService;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.event.EventListener;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
|
||||
/**
|
||||
* @author
|
||||
* 异步监听日志事件
|
||||
*/
|
||||
@Slf4j
|
||||
public class OperationLogListener {
|
||||
|
||||
@Autowired
|
||||
private OperationLogSaveService operationLogSaveService;
|
||||
|
||||
@Async
|
||||
@Order
|
||||
@EventListener(OperationLogEvent.class)
|
||||
public void saveSysLog(OperationLogEvent event) {
|
||||
operationLogSaveService.saveLog(event.getOperationLogDTO());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package cn.iocoder.mall.system.biz.log.operation.model.dto;
|
||||
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import io.swagger.annotations.ApiModelProperty;
|
||||
import lombok.Data;
|
||||
import lombok.experimental.Accessors;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 操作日志
|
||||
*
|
||||
* @author hccake
|
||||
* @date 2020-05-15 15:12:53
|
||||
*/
|
||||
@Data
|
||||
@Accessors(chain = true)
|
||||
@ApiModel(value = "操作日志")
|
||||
public class OperationLogDTO{
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 链路追踪编号
|
||||
*/
|
||||
@ApiModelProperty(value = "链路追踪编号")
|
||||
private String traceId;
|
||||
/**
|
||||
* 账号编号
|
||||
*/
|
||||
@ApiModelProperty(value = "账号编号")
|
||||
private Integer accountId;
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
@ApiModelProperty(value = "应用名")
|
||||
private String applicationName;
|
||||
/**
|
||||
* 访问地址
|
||||
*/
|
||||
@ApiModelProperty(value = "访问地址")
|
||||
private String uri;
|
||||
/**
|
||||
* 参数
|
||||
*/
|
||||
@ApiModelProperty(value = "参数")
|
||||
private String params;
|
||||
/**
|
||||
* http 方法
|
||||
*/
|
||||
@ApiModelProperty(value = "http 方法")
|
||||
private String method;
|
||||
/**
|
||||
* userAgent
|
||||
*/
|
||||
@ApiModelProperty(value = "userAgent")
|
||||
private String userAgent;
|
||||
/**
|
||||
* ip
|
||||
*/
|
||||
@ApiModelProperty(value = "ip")
|
||||
private String ip;
|
||||
/**
|
||||
* 请求时间
|
||||
*/
|
||||
@ApiModelProperty(value = "请求时间")
|
||||
private LocalDateTime startTime;
|
||||
/**
|
||||
* 响应时长 -- 毫秒级
|
||||
*/
|
||||
@ApiModelProperty(value = "响应时长 -- 毫秒级")
|
||||
private Integer responseTime;
|
||||
/**
|
||||
* 日志消息
|
||||
*/
|
||||
@ApiModelProperty(value = "日志消息")
|
||||
private String msg;
|
||||
/**
|
||||
* 操作状态
|
||||
*/
|
||||
@ApiModelProperty(value = "操作状态")
|
||||
private Integer status;
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
@ApiModelProperty(value = "创建者")
|
||||
private String operator;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package cn.iocoder.mall.system.biz.log.operation.model.po;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.FieldFill;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.baomidou.mybatisplus.extension.activerecord.Model;
|
||||
import io.swagger.annotations.ApiModel;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 操作日志
|
||||
*
|
||||
* @author hccake
|
||||
* @date 2020-05-15 15:12:53
|
||||
*/
|
||||
@Data
|
||||
@TableName("operation_log")
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ApiModel(value = "操作日志")
|
||||
public class OperationLogPO extends Model<OperationLogPO> {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* 编号
|
||||
*/
|
||||
@TableId
|
||||
private Integer id;
|
||||
/**
|
||||
* 链路追踪编号
|
||||
*/
|
||||
private String traceId;
|
||||
/**
|
||||
* 账号编号
|
||||
*/
|
||||
private Integer accountId;
|
||||
/**
|
||||
* 应用名
|
||||
*/
|
||||
private String applicationName;
|
||||
/**
|
||||
* 访问地址
|
||||
*/
|
||||
private String uri;
|
||||
/**
|
||||
* 参数
|
||||
*/
|
||||
private String params;
|
||||
/**
|
||||
* http 方法
|
||||
*/
|
||||
private String method;
|
||||
/**
|
||||
* userAgent
|
||||
*/
|
||||
private String userAgent;
|
||||
/**
|
||||
* ip
|
||||
*/
|
||||
private String ip;
|
||||
/**
|
||||
* 请求时间
|
||||
*/
|
||||
private LocalDateTime startTime;
|
||||
/**
|
||||
* 响应时长 -- 毫秒级
|
||||
*/
|
||||
private Integer responseTime;
|
||||
/**
|
||||
* 日志消息
|
||||
*/
|
||||
private String msg;
|
||||
/**
|
||||
* 操作状态
|
||||
*/
|
||||
private Integer status;
|
||||
/**
|
||||
* 创建者
|
||||
*/
|
||||
private String operator;
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
@TableField(fill = FieldFill.INSERT)
|
||||
private LocalDateTime createTime;
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package cn.iocoder.mall.system.biz.log.operation.service;
|
||||
|
||||
|
||||
import cn.iocoder.mall.system.biz.log.operation.model.dto.OperationLogDTO;
|
||||
|
||||
/**
|
||||
* 操作日志业务类
|
||||
* @author Hccake
|
||||
* @version 1.0
|
||||
* @date 2019/10/15 19:57
|
||||
*/
|
||||
public interface OperationLogSaveService {
|
||||
|
||||
/**
|
||||
* 保存操作日志
|
||||
* @param operationLogDTO
|
||||
* @return true/false
|
||||
*/
|
||||
boolean saveLog(OperationLogDTO operationLogDTO);
|
||||
}
|
Loading…
Reference in New Issue