完成操作日志的迁移

This commit is contained in:
YunaiV 2021-01-17 22:18:55 +08:00
parent 1768d27e11
commit e330bf0f39
14 changed files with 224 additions and 49 deletions

View File

@ -14,6 +14,7 @@ export function exportOperateLog(query) {
return request({
url: '/system/operate-log/export',
method: 'get',
params: query
params: query,
responseType: 'blob'
})
}

View File

@ -138,36 +138,41 @@
<el-dialog title="操作日志详细" :visible.sync="open" width="700px" append-to-body>
<el-form ref="form" :model="form" label-width="100px" size="mini">
<el-row>
<el-col :span="12">
<el-form-item label="操作模块:">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
<el-form-item
label="登录信息:"
>{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="请求地址:">{{ form.operUrl }}</el-form-item>
<el-form-item label="请求方式:">{{ form.requestMethod }}</el-form-item>
<el-col :span="24">
<el-form-item label="日志主键:">{{ form.id }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="操作方法:">{{ form.method }}</el-form-item>
<el-form-item label="链路追踪:">{{ form.traceId }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="请求参数:">{{ form.operParam }}</el-form-item>
<el-form-item label="用户信息:">{{ form.userId }} | {{ form.userNickname }} | {{ form.userIp }} | {{ form.userAgent}} </el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="返回参数:">{{ form.jsonResult }}</el-form-item>
<el-form-item label="操作信息:">
{{ form.module }} | {{ form.name }} | {{ getDictDataLabel(DICT_TYPE.SYS_OPERATE_TYPE, form.type) }}
<br /> {{ form.content }}
<br /> {{ form.exts }}
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="操作状态:">
<div v-if="form.status === 0">正常</div>
<div v-else-if="form.status === 1">失败</div>
<el-col :span="24">
<el-form-item label="请求信息:">{{ form.requestMethod }} | {{ form.requestUrl }} </el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="方法名:">{{ form.javaMethod }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="方法参数:">{{ form.javaMethodArgs }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="开始时间:">
{{ parseTime(form.startTime) }} | {{ form.duration }} ms
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="操作时间:">{{ parseTime(form.operTime) }}</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="异常信息:" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
<el-form-item label="操作结果:">
<div v-if="form.resultCode === 0">正常 | {{ form.resultData}} </div>
<div v-else-if="form.resultCode > 0">失败 | {{ form.resultCode }} || {{ form.resultMsg}}</div>
</el-form-item>
</el-col>
</el-row>
</el-form>
@ -258,7 +263,10 @@ export default {
},
/** 导出按钮操作 */
handleExport() {
const queryParams = this.queryParams;
const queryParams = this.addDateRange(this.queryParams, [
this.dateRange[0] ? this.dateRange[0] + ' 00:00:00' : undefined,
this.dateRange[1] ? this.dateRange[1] + ' 23:59:59' : undefined,
])
this.$confirm('是否确认导出所有操作日志数据项?', "警告", {
confirmButtonText: "确定",
cancelButtonText: "取消",
@ -266,7 +274,7 @@ export default {
}).then(function() {
return exportOperateLog(queryParams);
}).then(response => {
this.download(response.msg);
this.downloadExcel(response, '操作日志.xls');
})
}
}

View File

@ -1,6 +1,6 @@
package cn.iocoder.dashboard.framework.logger.operatelog.core.annotations;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
@ -32,7 +32,7 @@ public @interface OperateLog {
*
* 实际并不是数组因为枚举不能设置 null 作为默认值
*/
OperateLogTypeEnum[] type() default {};
OperateTypeEnum[] type() default {};
// ========== 开关字段 ==========

View File

@ -6,7 +6,7 @@ import cn.hutool.core.util.StrUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils;
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
@ -163,8 +163,14 @@ public class OperateLogAspect {
if (StrUtil.isEmpty(operateLogVO.getModule())) {
Api api = getClassAnnotation(joinPoint, Api.class);
if (api != null) {
operateLogVO.setModule(Optional.of(api.value())
.orElse(ArrayUtil.isEmpty(api.tags()) ? api.tags()[0] : null));
// 优先读取 @API name 属性
if (StrUtil.isNotEmpty(api.value())) {
operateLogVO.setModule(api.value());
}
// 没有的话读取 @API tags 属性
if (StrUtil.isEmpty(operateLogVO.getModule()) && ArrayUtil.isNotEmpty(api.tags())) {
operateLogVO.setModule(api.tags()[0]);
}
}
}
// name 属性
@ -180,7 +186,7 @@ public class OperateLogAspect {
}
if (operateLogVO.getType() == null) {
RequestMethod requestMethod = obtainFirstMatchRequestMethod(obtainRequestMethod(joinPoint));
OperateLogTypeEnum operateLogType = convertOperateLogType(requestMethod);
OperateTypeEnum operateLogType = convertOperateLogType(requestMethod);
operateLogVO.setType(operateLogType != null ? operateLogType.getType() : null);
}
// content exts 属性
@ -275,21 +281,21 @@ public class OperateLogAspect {
return requestMethods[0];
}
private static OperateLogTypeEnum convertOperateLogType(RequestMethod requestMethod) {
private static OperateTypeEnum convertOperateLogType(RequestMethod requestMethod) {
if (requestMethod == null) {
return null;
}
switch (requestMethod) {
case GET:
return OperateLogTypeEnum.GET;
return OperateTypeEnum.GET;
case POST:
return OperateLogTypeEnum.CREATE;
return OperateTypeEnum.CREATE;
case PUT:
return OperateLogTypeEnum.UPDATE;
return OperateTypeEnum.UPDATE;
case DELETE:
return OperateLogTypeEnum.DELETE;
return OperateTypeEnum.DELETE;
default:
return OperateLogTypeEnum.OTHER;
return OperateTypeEnum.OTHER;
}
}
@ -322,7 +328,7 @@ public class OperateLogAspect {
// 被忽略时标记为 ignore 字符串避免和 null 混在一起
args.put(argName, !isIgnoreArgs(argValue) ? argValue : "[ignore]");
}
return JSON.toJSONString(argValues);
return JSON.toJSONString(args);
}
private static String obtainResultData(Object result) {

View File

@ -11,7 +11,7 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum OperateLogTypeEnum {
public enum OperateTypeEnum {
/**
* 查询

View File

@ -2,9 +2,12 @@ package cn.iocoder.dashboard.modules.system.controller.logger;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.excel.core.util.ExcelUtils;
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.util.OperateLogUtils;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogExcelVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogExportReqVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogPageReqVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogRespVO;
import cn.iocoder.dashboard.modules.system.convert.logger.SysOperateLogConvert;
@ -22,12 +25,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import static cn.iocoder.dashboard.common.pojo.CommonResult.success;
import static cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum.EXPORT;
@Api(tags = "操作日志 API")
@RestController
@ -41,7 +47,7 @@ public class SysOperateLogController {
private SysUserService userService;
@ApiOperation("示例")
@OperateLog(type = OperateLogTypeEnum.OTHER)
@OperateLog(type = OperateTypeEnum.OTHER)
@GetMapping("/demo")
public CommonResult<Boolean> demo() {
// 这里可以调用业务逻辑
@ -74,13 +80,22 @@ public class SysOperateLogController {
return success(new PageResult<>(list, pageResult.getTotal()));
}
// @Log(title = "操作日志", businessType = BusinessType.EXPORT)
@ApiOperation("导出操作日志")
@GetMapping("/export")
@OperateLog(type = EXPORT)
// @PreAuthorize("@ss.hasPermi('system:operate-log:export')")
// @GetMapping("/export")
// public AjaxResult export(SysOperLog operLog) {
// List<SysOperLog> list = operLogService.selectOperLogList(operLog);
// ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
// return util.exportExcel(list, "操作日志");
// }
public void exportOperateLog(HttpServletResponse response, @Validated SysOperateLogExportReqVO reqVO)
throws IOException {
List<SysOperateLogDO> list = operateLogService.listOperateLogs(reqVO);
// 获得拼接需要的数据
Collection<Long> userIds = CollectionUtils.convertList(list, SysOperateLogDO::getUserId);
Map<Long, SysUserDO> userMap = userService.getUserMap(userIds);
// 拼接数据
List<SysOperateLogExcelVO> excelDataList = SysOperateLogConvert.INSTANCE.convertList(list, userMap);
// 输出
ExcelUtils.write(response, "操作日志.xls", "数据列表",
SysOperateLogExcelVO.class, excelDataList);
}
}

View File

@ -0,0 +1,42 @@
package cn.iocoder.dashboard.modules.system.controller.logger.vo;
import cn.iocoder.dashboard.framework.excel.core.annotations.DictFormat;
import cn.iocoder.dashboard.framework.excel.core.convert.DictConvert;
import cn.iocoder.dashboard.modules.system.enums.dict.DictTypeEnum;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
/**
* 操作日志 Excel 导出响应 VO
*/
@Data
public class SysOperateLogExcelVO {
@ExcelProperty("日志编号")
private Long id;
@ExcelProperty("操作模块")
private String module;
@ExcelProperty("操作名")
private String name;
@ExcelProperty(value = "操作类型", converter = DictConvert.class)
@DictFormat(DictTypeEnum.SYS_OPERATE_TYPE)
private String type;
@ExcelProperty("操作人")
private String userNickname;
@ExcelProperty(value = "操作结果") // 成功 or 失败
private String successStr;
@ExcelProperty("操作日志")
private Date startTime;
@ExcelProperty("执行时长")
private Integer duration;
}

View File

@ -0,0 +1,36 @@
package cn.iocoder.dashboard.modules.system.controller.logger.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.util.Date;
import static cn.iocoder.dashboard.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@ApiModel("操作日志分页列表 Request VO")
@Data
public class SysOperateLogExportReqVO {
@ApiModelProperty(value = "操作模块", example = "订单", notes = "模拟匹配")
private String module;
@ApiModelProperty(value = "用户昵称", example = "芋道", notes = "模拟匹配")
private String userNickname;
@ApiModelProperty(value = "操作分类", example = "1", notes = "参见 SysOperateLogTypeEnum 枚举类")
private Integer type;
@ApiModelProperty(value = "操作状态", example = "true")
private Boolean success;
@ApiModelProperty(value = "开始时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date beginTime;
@ApiModelProperty(value = "结束时间", example = "2020-10-24")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private Date endTime;
}

View File

@ -2,11 +2,20 @@ package cn.iocoder.dashboard.modules.system.convert.logger;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogExcelVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogRespVO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
import cn.iocoder.dashboard.util.collection.MapUtils;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import static cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
@Mapper
public interface SysOperateLogConvert {
@ -18,4 +27,15 @@ public interface SysOperateLogConvert {
SysOperateLogRespVO convert(SysOperateLogDO bean);
default List<SysOperateLogExcelVO> convertList(List<SysOperateLogDO> list, Map<Long, SysUserDO> userMap) {
return list.stream().map(operateLog -> {
SysOperateLogExcelVO excelVO = convert02(operateLog);
MapUtils.findAndThen(userMap, operateLog.getId(), user -> excelVO.setUserNickname(user.getNickname()));
excelVO.setSuccessStr(SUCCESS.getCode().equals(operateLog.getResultCode()) ? "成功" : "失败");
return excelVO;
}).collect(Collectors.toList());
}
SysOperateLogExcelVO convert02(SysOperateLogDO bean);
}

View File

@ -4,11 +4,13 @@ import cn.iocoder.dashboard.common.exception.enums.GlobalErrorCodeConstants;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.dashboard.framework.mybatis.core.query.QueryWrapperX;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogExportReqVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogPageReqVO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
import java.util.List;
@Mapper
public interface SysOperateLogMapper extends BaseMapperX<SysOperateLogDO> {
@ -24,7 +26,23 @@ public interface SysOperateLogMapper extends BaseMapperX<SysOperateLogDO> {
} else if (Boolean.FALSE.equals(reqVO.getSuccess())) {
query.gt("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
}
query.orderByDesc("id"); // 降序
return selectPage(reqVO, query);
}
default List<SysOperateLogDO> selectList(SysOperateLogExportReqVO reqVO, Collection<Long> userIds) {
QueryWrapperX<SysOperateLogDO> query = new QueryWrapperX<SysOperateLogDO>()
.likeIfPresent("module", reqVO.getModule())
.inIfPresent("user_id", userIds)
.eqIfPresent("operate_type", reqVO.getType())
.betweenIfPresent("start_time", reqVO.getBeginTime(), reqVO.getEndTime());
if (Boolean.TRUE.equals(reqVO.getSuccess())) {
query.eq("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
} else if (Boolean.FALSE.equals(reqVO.getSuccess())) {
query.gt("result_code", GlobalErrorCodeConstants.SUCCESS.getCode());
}
query.orderByDesc("id"); // 降序
return selectList(query);
}
}

View File

@ -3,7 +3,7 @@ package cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger;
import cn.iocoder.dashboard.common.pojo.CommonResult;
import cn.iocoder.dashboard.framework.mybatis.core.dataobject.BaseDO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -19,7 +19,7 @@ import java.util.Map;
*
* @author 芋道源码
*/
@TableName("sys_operate_log")
@TableName(value = "sys_operate_log", autoResultMap = true)
@Data
@EqualsAndHashCode(callSuper = true)
public class SysOperateLogDO extends BaseDO {
@ -62,7 +62,7 @@ public class SysOperateLogDO extends BaseDO {
/**
* 操作分类
*
* 枚举 {@link OperateLogTypeEnum}
* 枚举 {@link OperateTypeEnum}
*/
@TableField("operate_type")
private Integer type;

View File

@ -12,6 +12,7 @@ public enum DictTypeEnum {
SYS_USER_SEX("sys_user_sex"), // 用户性别
SYS_COMMON_STATUS("sys_common_status"), // 系统状态
SYS_OPERATE_TYPE("sys_operate_type"), // 操作类型
;

View File

@ -2,9 +2,12 @@ package cn.iocoder.dashboard.modules.system.service.logger;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.logger.operatelog.core.service.OperateLogFrameworkService;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogExportReqVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogPageReqVO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
import java.util.List;
/**
* 操作日志 Service 接口
*/
@ -18,4 +21,12 @@ public interface SysOperateLogService extends OperateLogFrameworkService {
*/
PageResult<SysOperateLogDO> pageOperateLog(SysOperateLogPageReqVO reqVO);
/**
* 获得操作日志列表
*
* @param reqVO 列表条件
* @return 日志列表
*/
List<SysOperateLogDO> listOperateLogs(SysOperateLogExportReqVO reqVO);
}

View File

@ -4,6 +4,7 @@ import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogCreateReqVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogExportReqVO;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogPageReqVO;
import cn.iocoder.dashboard.modules.system.convert.logger.SysOperateLogConvert;
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger.SysOperateLogMapper;
@ -18,6 +19,8 @@ import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO.JAVA_METHOD_ARGS_MAX_LENGTH;
import static cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO.RESULT_MAX_LENGTH;
@ -61,4 +64,18 @@ public class SysOperateLogServiceImpl implements SysOperateLogService {
return operateLogMapper.selectPage(reqVO, userIds);
}
@Override
public List<SysOperateLogDO> listOperateLogs(SysOperateLogExportReqVO reqVO) {
// 处理基于用户昵称的查询
Collection<Long> userIds = null;
if (StrUtil.isNotEmpty(reqVO.getUserNickname())) {
userIds = convertSet(userService.listUsersByNickname(reqVO.getUserNickname()), SysUserDO::getId);
if (CollUtil.isEmpty(userIds)) {
return Collections.emptyList();
}
}
// 查询列表
return operateLogMapper.selectList(reqVO, userIds);
}
}