优化 yudao-spring-boot-starter-biz-operatelog 的封装,和 yudao-cloud 保持一致

This commit is contained in:
YunaiV 2022-06-13 23:05:13 +08:00
parent b1aa9f484f
commit e68d4f54f7
15 changed files with 423 additions and 177 deletions

View File

@ -34,6 +34,13 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<!-- 业务组件 -->
<dependency>
<groupId>cn.iocoder.boot</groupId>
<artifactId>yudao-module-system-api</artifactId> <!-- 需要使用它,进行操作日志的记录 -->
<version>${revision}</version>
</dependency>
<!-- 工具类相关 --> <!-- 工具类相关 -->
<dependency> <dependency>
<groupId>com.google.guava</groupId> <groupId>com.google.guava</groupId>

View File

@ -1,6 +1,9 @@
package cn.iocoder.yudao.framework.operatelog.config; package cn.iocoder.yudao.framework.operatelog.config;
import cn.iocoder.yudao.framework.operatelog.core.aop.OperateLogAspect; import cn.iocoder.yudao.framework.operatelog.core.aop.OperateLogAspect;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkServiceImpl;
import cn.iocoder.yudao.module.system.api.logger.OperateLogApi;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
@ -12,4 +15,9 @@ public class YudaoOperateLogAutoConfiguration {
return new OperateLogAspect(); return new OperateLogAspect();
} }
@Bean
public OperateLogFrameworkService operateLogFrameworkService(OperateLogApi operateLogApi) {
return new OperateLogFrameworkServiceImpl(operateLogApi);
}
} }

View File

@ -9,9 +9,8 @@ import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.json.JsonUtils; import cn.iocoder.yudao.framework.common.util.json.JsonUtils;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils; import cn.iocoder.yudao.framework.common.util.servlet.ServletUtils;
import cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum; import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService; import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils; import cn.iocoder.yudao.framework.web.core.util.WebFrameworkUtils;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
@ -57,13 +56,13 @@ public class OperateLogAspect {
/** /**
* 用于记录操作内容的上下文 * 用于记录操作内容的上下文
* *
* @see OperateLogCreateReqDTO#getContent() * @see OperateLog#getContent()
*/ */
private static final ThreadLocal<String> CONTENT = new ThreadLocal<>(); private static final ThreadLocal<String> CONTENT = new ThreadLocal<>();
/** /**
* 用于记录拓展字段的上下文 * 用于记录拓展字段的上下文
* *
* @see OperateLogCreateReqDTO#getExts() * @see OperateLog#getExts()
*/ */
private static final ThreadLocal<Map<String, Object>> EXTS = new ThreadLocal<>(); private static final ThreadLocal<Map<String, Object>> EXTS = new ThreadLocal<>();
@ -73,16 +72,20 @@ public class OperateLogAspect {
@Around("@annotation(apiOperation)") @Around("@annotation(apiOperation)")
public Object around(ProceedingJoinPoint joinPoint, ApiOperation apiOperation) throws Throwable { public Object around(ProceedingJoinPoint joinPoint, ApiOperation apiOperation) throws Throwable {
// 可能也添加了 @ApiOperation 注解 // 可能也添加了 @ApiOperation 注解
OperateLog operateLog = getMethodAnnotation(joinPoint, OperateLog.class); cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog = getMethodAnnotation(joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog.class);
return around0(joinPoint, operateLog, apiOperation); return around0(joinPoint, operateLog, apiOperation);
} }
@Around("!@annotation(io.swagger.annotations.ApiOperation) && @annotation(operateLog)") // 兼容处理只添加 @OperateLog 注解的情况 @Around("!@annotation(io.swagger.annotations.ApiOperation) && @annotation(operateLog)") // 兼容处理只添加 @OperateLog 注解的情况
public Object around(ProceedingJoinPoint joinPoint, OperateLog operateLog) throws Throwable { public Object around(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog) throws Throwable {
return around0(joinPoint, operateLog, null); return around0(joinPoint, operateLog, null);
} }
private Object around0(ProceedingJoinPoint joinPoint, OperateLog operateLog, ApiOperation apiOperation) throws Throwable { private Object around0(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
ApiOperation apiOperation) throws Throwable {
// 目前只有管理员才记录操作日志所以非管理员直接调用不进行记录 // 目前只有管理员才记录操作日志所以非管理员直接调用不进行记录
Integer userType = WebFrameworkUtils.getLoginUserType(); Integer userType = WebFrameworkUtils.getLoginUserType();
if (!Objects.equals(userType, UserTypeEnum.ADMIN.getValue())) { if (!Objects.equals(userType, UserTypeEnum.ADMIN.getValue())) {
@ -121,7 +124,9 @@ public class OperateLogAspect {
EXTS.remove(); EXTS.remove();
} }
private void log(ProceedingJoinPoint joinPoint, OperateLog operateLog, ApiOperation apiOperation, private void log(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
ApiOperation apiOperation,
Date startTime, Object result, Throwable exception) { Date startTime, Object result, Throwable exception) {
try { try {
// 判断不记录的情况 // 判断不记录的情况
@ -136,113 +141,119 @@ public class OperateLogAspect {
} }
} }
private void log0(ProceedingJoinPoint joinPoint, OperateLog operateLog, ApiOperation apiOperation, private void log0(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
ApiOperation apiOperation,
Date startTime, Object result, Throwable exception) { Date startTime, Object result, Throwable exception) {
OperateLogCreateReqDTO operateLogDTO = new OperateLogCreateReqDTO(); OperateLog operateLogObj = new OperateLog();
// 补全通用字段 // 补全通用字段
operateLogDTO.setTraceId(TracerUtils.getTraceId()); operateLogObj.setTraceId(TracerUtils.getTraceId());
operateLogDTO.setStartTime(startTime); operateLogObj.setStartTime(startTime);
// 补充用户信息 // 补充用户信息
fillUserFields(operateLogDTO); fillUserFields(operateLogObj);
// 补全模块信息 // 补全模块信息
fillModuleFields(operateLogDTO, joinPoint, operateLog, apiOperation); fillModuleFields(operateLogObj, joinPoint, operateLog, apiOperation);
// 补全请求信息 // 补全请求信息
fillRequestFields(operateLogDTO); fillRequestFields(operateLogObj);
// 补全方法信息 // 补全方法信息
fillMethodFields(operateLogDTO, joinPoint, operateLog, startTime, result, exception); fillMethodFields(operateLogObj, joinPoint, operateLog, startTime, result, exception);
// 异步记录日志 // 异步记录日志
operateLogFrameworkService.createOperateLogAsync(operateLogDTO); operateLogFrameworkService.createOperateLog(operateLogObj);
} }
private static void fillUserFields(OperateLogCreateReqDTO operateLogDTO) { private static void fillUserFields(OperateLog operateLogObj) {
operateLogDTO.setUserId(WebFrameworkUtils.getLoginUserId()); operateLogObj.setUserId(WebFrameworkUtils.getLoginUserId());
operateLogDTO.setUserType(WebFrameworkUtils.getLoginUserType()); operateLogObj.setUserType(WebFrameworkUtils.getLoginUserType());
} }
private static void fillModuleFields(OperateLogCreateReqDTO operateLogDTO, private static void fillModuleFields(OperateLog operateLogObj,
ProceedingJoinPoint joinPoint, OperateLog operateLog, ApiOperation apiOperation) { ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
ApiOperation apiOperation) {
// module 属性 // module 属性
if (operateLog != null) { if (operateLog != null) {
operateLogDTO.setModule(operateLog.module()); operateLogObj.setModule(operateLog.module());
} }
if (StrUtil.isEmpty(operateLogDTO.getModule())) { if (StrUtil.isEmpty(operateLogObj.getModule())) {
Api api = getClassAnnotation(joinPoint, Api.class); Api api = getClassAnnotation(joinPoint, Api.class);
if (api != null) { if (api != null) {
// 优先读取 @API name 属性 // 优先读取 @API name 属性
if (StrUtil.isNotEmpty(api.value())) { if (StrUtil.isNotEmpty(api.value())) {
operateLogDTO.setModule(api.value()); operateLogObj.setModule(api.value());
} }
// 没有的话读取 @API tags 属性 // 没有的话读取 @API tags 属性
if (StrUtil.isEmpty(operateLogDTO.getModule()) && ArrayUtil.isNotEmpty(api.tags())) { if (StrUtil.isEmpty(operateLogObj.getModule()) && ArrayUtil.isNotEmpty(api.tags())) {
operateLogDTO.setModule(api.tags()[0]); operateLogObj.setModule(api.tags()[0]);
} }
} }
} }
// name 属性 // name 属性
if (operateLog != null) { if (operateLog != null) {
operateLogDTO.setName(operateLog.name()); operateLogObj.setName(operateLog.name());
} }
if (StrUtil.isEmpty(operateLogDTO.getName()) && apiOperation != null) { if (StrUtil.isEmpty(operateLogObj.getName()) && apiOperation != null) {
operateLogDTO.setName(apiOperation.value()); operateLogObj.setName(apiOperation.value());
} }
// type 属性 // type 属性
if (operateLog != null && ArrayUtil.isNotEmpty(operateLog.type())) { if (operateLog != null && ArrayUtil.isNotEmpty(operateLog.type())) {
operateLogDTO.setType(operateLog.type()[0].getType()); operateLogObj.setType(operateLog.type()[0].getType());
} }
if (operateLogDTO.getType() == null) { if (operateLogObj.getType() == null) {
RequestMethod requestMethod = obtainFirstMatchRequestMethod(obtainRequestMethod(joinPoint)); RequestMethod requestMethod = obtainFirstMatchRequestMethod(obtainRequestMethod(joinPoint));
OperateTypeEnum operateLogType = convertOperateLogType(requestMethod); OperateTypeEnum operateLogType = convertOperateLogType(requestMethod);
operateLogDTO.setType(operateLogType != null ? operateLogType.getType() : null); operateLogObj.setType(operateLogType != null ? operateLogType.getType() : null);
} }
// content exts 属性 // content exts 属性
operateLogDTO.setContent(CONTENT.get()); operateLogObj.setContent(CONTENT.get());
operateLogDTO.setExts(EXTS.get()); operateLogObj.setExts(EXTS.get());
} }
private static void fillRequestFields(OperateLogCreateReqDTO operateLogDTO) { private static void fillRequestFields(OperateLog operateLogObj) {
// 获得 Request 对象 // 获得 Request 对象
HttpServletRequest request = ServletUtils.getRequest(); HttpServletRequest request = ServletUtils.getRequest();
if (request == null) { if (request == null) {
return; return;
} }
// 补全请求信息 // 补全请求信息
operateLogDTO.setRequestMethod(request.getMethod()); operateLogObj.setRequestMethod(request.getMethod());
operateLogDTO.setRequestUrl(request.getRequestURI()); operateLogObj.setRequestUrl(request.getRequestURI());
operateLogDTO.setUserIp(ServletUtil.getClientIP(request)); operateLogObj.setUserIp(ServletUtil.getClientIP(request));
operateLogDTO.setUserAgent(ServletUtils.getUserAgent(request)); operateLogObj.setUserAgent(ServletUtils.getUserAgent(request));
} }
private static void fillMethodFields(OperateLogCreateReqDTO operateLogDTO, private static void fillMethodFields(OperateLog operateLogObj,
ProceedingJoinPoint joinPoint, OperateLog operateLog, ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog,
Date startTime, Object result, Throwable exception) { Date startTime, Object result, Throwable exception) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
operateLogDTO.setJavaMethod(methodSignature.toString()); operateLogObj.setJavaMethod(methodSignature.toString());
if (operateLog == null || operateLog.logArgs()) { if (operateLog == null || operateLog.logArgs()) {
operateLogDTO.setJavaMethodArgs(obtainMethodArgs(joinPoint)); operateLogObj.setJavaMethodArgs(obtainMethodArgs(joinPoint));
} }
if (operateLog == null || operateLog.logResultData()) { if (operateLog == null || operateLog.logResultData()) {
operateLogDTO.setResultData(obtainResultData(result)); operateLogObj.setResultData(obtainResultData(result));
} }
operateLogDTO.setDuration((int) (System.currentTimeMillis() - startTime.getTime())); operateLogObj.setDuration((int) (System.currentTimeMillis() - startTime.getTime()));
// 正常处理 resultCode resultMsg 字段 // 正常处理 resultCode resultMsg 字段
if (result != null) { if (result != null) {
if (result instanceof CommonResult) { if (result instanceof CommonResult) {
CommonResult<?> commonResult = (CommonResult<?>) result; CommonResult<?> commonResult = (CommonResult<?>) result;
operateLogDTO.setResultCode(commonResult.getCode()); operateLogObj.setResultCode(commonResult.getCode());
operateLogDTO.setResultMsg(commonResult.getMsg()); operateLogObj.setResultMsg(commonResult.getMsg());
} else { } else {
operateLogDTO.setResultCode(SUCCESS.getCode()); operateLogObj.setResultCode(SUCCESS.getCode());
} }
} }
// 异常处理 resultCode resultMsg 字段 // 异常处理 resultCode resultMsg 字段
if (exception != null) { if (exception != null) {
operateLogDTO.setResultCode(INTERNAL_SERVER_ERROR.getCode()); operateLogObj.setResultCode(INTERNAL_SERVER_ERROR.getCode());
operateLogDTO.setResultMsg(ExceptionUtil.getRootCauseMessage(exception)); operateLogObj.setResultMsg(ExceptionUtil.getRootCauseMessage(exception));
} }
} }
private static boolean isLogEnable(ProceedingJoinPoint joinPoint, OperateLog operateLog) { private static boolean isLogEnable(ProceedingJoinPoint joinPoint,
cn.iocoder.yudao.framework.operatelog.core.annotations.OperateLog operateLog) {
// @OperateLog 注解的情况下 // @OperateLog 注解的情况下
if (operateLog != null) { if (operateLog != null) {
return operateLog.enable(); return operateLog.enable();

View File

@ -1,87 +0,0 @@
package cn.iocoder.yudao.framework.operatelog.core.dto;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.Map;
/**
* 操作日志创建 Request DTO
*/
@Data
public class OperateLogCreateReqDTO {
@ApiModelProperty(value = "链路追踪编号", required = true, example = "89aca178-a370-411c-ae02-3f0d672be4ab")
@NotEmpty(message = "链路追踪编号不能为空")
private String traceId;
@ApiModelProperty(value = "用户编号", required = true, example = "1024")
@NotNull(message = "用户编号不能为空")
private Long userId;
@ApiModelProperty(value = "用户类型", required = true, example = "1")
@NotNull(message = "用户类型不能为空")
private Integer userType;
@ApiModelProperty(value = "操作模块", required = true, example = "订单")
@NotEmpty(message = "操作模块不能为空")
private String module;
@ApiModelProperty(value = "操作名", required = true, example = "创建订单")
@NotEmpty(message = "操作名")
private String name;
@ApiModelProperty(value = "操作分类", required = true, example = "1", notes = "参见 SysOperateLogTypeEnum 枚举类")
@NotNull(message = "操作分类不能为空")
private Integer type;
@ApiModelProperty(value = "操作明细", example = "修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。")
private String content;
@ApiModelProperty(value = "拓展字段", example = "{'orderId': 1}")
private Map<String, Object> exts;
@ApiModelProperty(value = "请求方法名", required = true, example = "GET")
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
@ApiModelProperty(value = "请求地址", required = true, example = "/xxx/yyy")
@NotEmpty(message = "请求地址不能为空")
private String requestUrl;
@ApiModelProperty(value = "用户 IP", required = true, example = "127.0.0.1")
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
@ApiModelProperty(value = "浏览器 UserAgent", required = true, example = "Mozilla/5.0")
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent;
@ApiModelProperty(value = "Java 方法名", required = true, example = "cn.iocoder.yudao.UserController.save(...)")
@NotEmpty(message = "Java 方法名不能为空")
private String javaMethod;
@ApiModelProperty(value = "Java 方法的参数")
private String javaMethodArgs;
@ApiModelProperty(value = "开始时间", required = true)
@NotNull(message = "开始时间不能为空")
private Date startTime;
@ApiModelProperty(value = "执行时长,单位:毫秒", required = true)
@NotNull(message = "执行时长不能为空")
private Integer duration;
@ApiModelProperty(value = "结果码", required = true)
@NotNull(message = "结果码不能为空")
private Integer resultCode;
@ApiModelProperty(value = "结果提示")
private String resultMsg;
@ApiModelProperty(value = "结果数据")
private String resultData;
}

View File

@ -0,0 +1,110 @@
package cn.iocoder.yudao.framework.operatelog.core.service;
import lombok.Data;
import java.util.Date;
import java.util.Map;
/**
* 操作日志
*
* @author 芋道源码
*/
@Data
public class OperateLog {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
private Long userId;
/**
* 用户类型
*/
private Integer userType;
/**
* 操作模块
*/
private String module;
/**
* 操作名
*/
private String name;
/**
* 操作分类
*/
private Integer type;
/**
* 操作明细
*/
private String content;
/**
* 拓展字段
*/
private Map<String, Object> exts;
/**
* 请求方法名
*/
private String requestMethod;
/**
* 请求地址
*/
private String requestUrl;
/**
* 用户 IP
*/
private String userIp;
/**
* 浏览器 UserAgent
*/
private String userAgent;
/**
* Java 方法名
*/
private String javaMethod;
/**
* Java 方法的参数
*/
private String javaMethodArgs;
/**
* 开始时间
*/
private Date startTime;
/**
* 执行时长单位毫秒
*/
private Integer duration;
/**
* 结果码
*/
private Integer resultCode;
/**
* 结果提示
*/
private String resultMsg;
/**
* 结果数据
*/
private String resultData;
}

View File

@ -1,17 +1,17 @@
package cn.iocoder.yudao.framework.operatelog.core.service; package cn.iocoder.yudao.framework.operatelog.core.service;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO; /**
* 操作日志 Framework Service 接口
import java.util.concurrent.Future; *
* @author 芋道源码
*/
public interface OperateLogFrameworkService { public interface OperateLogFrameworkService {
/** /**
* 异步记录操作日志 * 记录操作日志
* *
* @param reqVO 操作日志请求 * @param operateLog 操作日志请求
* @return true: 记录成功,false: 记录失败
*/ */
Future<Boolean> createOperateLogAsync(OperateLogCreateReqDTO reqVO); void createOperateLog(OperateLog operateLog);
} }

View File

@ -0,0 +1,28 @@
package cn.iocoder.yudao.framework.operatelog.core.service;
import cn.hutool.core.bean.BeanUtil;
import cn.iocoder.yudao.module.system.api.logger.OperateLogApi;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import lombok.RequiredArgsConstructor;
import org.springframework.scheduling.annotation.Async;
/**
* 操作日志 Framework Service 实现类
*
* 基于 {@link OperateLogApi} 实现记录操作日志
*
* @author 芋道源码
*/
@RequiredArgsConstructor
public class OperateLogFrameworkServiceImpl implements OperateLogFrameworkService {
private final OperateLogApi operateLogApi;
@Override
@Async
public void createOperateLog(OperateLog operateLog) {
OperateLogCreateReqDTO reqDTO = BeanUtil.copyProperties(operateLog, OperateLogCreateReqDTO.class);
operateLogApi.createOperateLog(reqDTO);
}
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import javax.validation.Valid;
/**
* 操作日志 API 接口
*
* @author 芋道源码
*/
public interface OperateLogApi {
/**
* 创建操作日志
*
* @param createReqDTO 请求
*/
void createOperateLog(@Valid OperateLogCreateReqDTO createReqDTO);
}

View File

@ -0,0 +1,123 @@
package cn.iocoder.yudao.module.system.api.logger.dto;
import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.Map;
/**
* 操作日志创建 Request DTO
*/
@Data
public class OperateLogCreateReqDTO {
/**
* 链路追踪编号
*/
private String traceId;
/**
* 用户编号
*/
@NotNull(message = "用户编号不能为空")
private Long userId;
/**
* 用户类型
*/
@NotNull(message = "用户类型不能为空")
private Integer userType;
/**
* 操作模块
*/
@NotEmpty(message = "操作模块不能为空")
private String module;
/**
* 操作名
*/
@NotEmpty(message = "操作名")
private String name;
/**
* 操作分类
*/
@NotNull(message = "操作分类不能为空")
private Integer type;
/**
* 操作明细
*/
private String content;
/**
* 拓展字段
*/
private Map<String, Object> exts;
/**
* 请求方法名
*/
@NotEmpty(message = "请求方法名不能为空")
private String requestMethod;
/**
* 请求地址
*/
@NotEmpty(message = "请求地址不能为空")
private String requestUrl;
/**
* 用户 IP
*/
@NotEmpty(message = "用户 IP 不能为空")
private String userIp;
/**
* 浏览器 UserAgent
*/
@NotEmpty(message = "浏览器 UserAgent 不能为空")
private String userAgent;
/**
* Java 方法名
*/
@NotEmpty(message = "Java 方法名不能为空")
private String javaMethod;
/**
* Java 方法的参数
*/
private String javaMethodArgs;
/**
* 开始时间
*/
@NotNull(message = "开始时间不能为空")
private Date startTime;
/**
* 执行时长单位毫秒
*/
@NotNull(message = "执行时长不能为空")
private Integer duration;
/**
* 结果码
*/
@NotNull(message = "结果码不能为空")
private Integer resultCode;
/**
* 结果提示
*/
private String resultMsg;
/**
* 结果数据
*/
private String resultData;
}

View File

@ -0,0 +1,27 @@
package cn.iocoder.yudao.module.system.api.logger;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.service.logger.OperateLogService;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
/**
* 操作日志 API 实现类
*
* @author 芋道源码
*/
@Service
@Validated
public class OperateLogApiImpl implements OperateLogApi {
@Resource
private OperateLogService operateLogService;
@Override
public void createOperateLog(OperateLogCreateReqDTO createReqDTO) {
operateLogService.createOperateLog(createReqDTO);
}
}

View File

@ -5,7 +5,8 @@ Content-Type: application/json
tenant-id: {{adminTenentId}} tenant-id: {{adminTenentId}}
{ {
"code": "test_01", "templateCode": "test_01",
"mobile": "156016913900",
"params": { "params": {
"key01": "value01", "key01": "value01",
"key02": "value02" "key02": "value02"

View File

@ -6,7 +6,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO; import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.MapUtils; import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import org.mapstruct.Mapper; import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers; import org.mapstruct.factory.Mappers;

View File

@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.system.service.logger; package cn.iocoder.yudao.module.system.service.logger;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLog;
import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService; import cn.iocoder.yudao.framework.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
@ -10,8 +12,17 @@ import java.util.List;
/** /**
* 操作日志 Service 接口 * 操作日志 Service 接口
*
* @author 芋道源码
*/ */
public interface OperateLogService extends OperateLogFrameworkService { public interface OperateLogService {
/**
* 记录操作日志
*
* @param createReqDTO 操作日志请求
*/
void createOperateLog(OperateLogCreateReqDTO createReqDTO);
/** /**
* 获得操作日志分页列表 * 获得操作日志分页列表

View File

@ -4,7 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil; import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.string.StrUtils; import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO; import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.convert.logger.OperateLogConvert; import cn.iocoder.yudao.module.system.convert.logger.OperateLogConvert;
@ -13,8 +13,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper; import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper;
import cn.iocoder.yudao.module.system.service.user.AdminUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.AsyncResult;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
@ -22,7 +20,6 @@ import javax.annotation.Resource;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.Future;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet; import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
import static cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO.JAVA_METHOD_ARGS_MAX_LENGTH; import static cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO.JAVA_METHOD_ARGS_MAX_LENGTH;
@ -40,19 +37,11 @@ public class OperateLogServiceImpl implements OperateLogService {
private AdminUserService userService; private AdminUserService userService;
@Override @Override
@Async public void createOperateLog(OperateLogCreateReqDTO createReqDTO) {
public Future<Boolean> createOperateLogAsync(OperateLogCreateReqDTO reqVO) { OperateLogDO logDO = OperateLogConvert.INSTANCE.convert(createReqDTO);
boolean success = false;
try {
OperateLogDO logDO = OperateLogConvert.INSTANCE.convert(reqVO);
logDO.setJavaMethodArgs(StrUtils.maxLength(logDO.getJavaMethodArgs(), JAVA_METHOD_ARGS_MAX_LENGTH)); logDO.setJavaMethodArgs(StrUtils.maxLength(logDO.getJavaMethodArgs(), JAVA_METHOD_ARGS_MAX_LENGTH));
logDO.setResultData(StrUtils.maxLength(logDO.getResultData(), RESULT_MAX_LENGTH)); logDO.setResultData(StrUtils.maxLength(logDO.getResultData(), RESULT_MAX_LENGTH));
success = operateLogMapper.insert(logDO) == 1; operateLogMapper.insert(logDO);
} catch (Throwable throwable) {
// 仅仅打印日志不对外抛出原因是还是要保留现场数据
log.error("[createOperateLogAsync][记录操作日志异常,日志为 ({})]", reqVO, throwable);
}
return new AsyncResult<>(success);
} }
@Override @Override

View File

@ -7,9 +7,10 @@ import cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstant
import cn.iocoder.yudao.framework.common.pojo.PageResult; import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils; import cn.iocoder.yudao.framework.common.util.monitor.TracerUtils;
import cn.iocoder.yudao.framework.common.util.object.ObjectUtils; import cn.iocoder.yudao.framework.common.util.object.ObjectUtils;
import cn.iocoder.yudao.framework.operatelog.core.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum; import cn.iocoder.yudao.framework.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import cn.iocoder.yudao.framework.test.core.util.RandomUtils; import cn.iocoder.yudao.framework.test.core.util.RandomUtils;
import cn.iocoder.yudao.module.system.api.logger.dto.OperateLogCreateReqDTO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogExportReqVO;
import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO; import cn.iocoder.yudao.module.system.controller.admin.logger.vo.operatelog.OperateLogPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO; import cn.iocoder.yudao.module.system.dal.dataobject.logger.OperateLogDO;
@ -17,7 +18,6 @@ import cn.iocoder.yudao.module.system.dal.dataobject.user.AdminUserDO;
import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper; import cn.iocoder.yudao.module.system.dal.mysql.logger.OperateLogMapper;
import cn.iocoder.yudao.module.system.enums.common.SexEnum; import cn.iocoder.yudao.module.system.enums.common.SexEnum;
import cn.iocoder.yudao.module.system.service.user.AdminUserService; import cn.iocoder.yudao.module.system.service.user.AdminUserService;
import cn.iocoder.yudao.framework.test.core.ut.BaseDbUnitTest;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import; import org.springframework.context.annotation.Import;
@ -25,8 +25,6 @@ import org.springframework.context.annotation.Import;
import javax.annotation.Resource; import javax.annotation.Resource;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import static cn.hutool.core.util.RandomUtil.randomEle; import static cn.hutool.core.util.RandomUtil.randomEle;
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST; import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.BAD_REQUEST;
@ -49,7 +47,7 @@ public class OperateLogServiceImplTest extends BaseDbUnitTest {
private AdminUserService userService; private AdminUserService userService;
@Test @Test
public void testCreateOperateLogAsync() throws InterruptedException, ExecutionException { public void testCreateOperateLogAsync() {
String traceId = TracerUtils.getTraceId(); String traceId = TracerUtils.getTraceId();
OperateLogCreateReqDTO reqVO = RandomUtils.randomPojo(OperateLogCreateReqDTO.class, o -> { OperateLogCreateReqDTO reqVO = RandomUtils.randomPojo(OperateLogCreateReqDTO.class, o -> {
o.setTraceId(traceId); o.setTraceId(traceId);
@ -59,8 +57,7 @@ public class OperateLogServiceImplTest extends BaseDbUnitTest {
}); });
// 执行service方法 // 执行service方法
Future<Boolean> future = operateLogServiceImpl.createOperateLogAsync(reqVO); operateLogServiceImpl.createOperateLog(reqVO);
future.get();
// 断言插入是否正确 // 断言插入是否正确
OperateLogDO sysOperateLogDO = operateLogMapper.selectOne("trace_id", traceId); OperateLogDO sysOperateLogDO = operateLogMapper.selectOne("trace_id", traceId);
assertPojoEquals(reqVO, sysOperateLogDO); assertPojoEquals(reqVO, sysOperateLogDO);