🎨 操作日志功能:生产日志部分

This commit is contained in:
hccake 2020-05-15 15:44:22 +08:00
parent 7dbe420d8d
commit 20e65bf2f7
9 changed files with 418 additions and 0 deletions

View File

@ -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>

View File

@ -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();
}

View File

@ -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());
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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());
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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);
}