完善新操作日志的页面修改

This commit is contained in:
YunaiV
2021-01-17 20:55:14 +08:00
parent 2fccaa2b9a
commit 1768d27e11
35 changed files with 648 additions and 663 deletions

View File

@ -31,4 +31,8 @@ public final class PageResult<T> implements Serializable {
this.total = total;
}
public static <T> PageResult<T> empty() {
return new PageResult<>(0L);
}
}

View File

@ -4,6 +4,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
@Configuration
@EnableAsync(proxyTargetClass = true)
@EnableAsync
public class AsyncConfiguration {
}

View File

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

View File

@ -6,11 +6,11 @@ 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.service.OperateLogFrameworkService;
import cn.iocoder.dashboard.framework.security.core.util.SecurityUtils;
import cn.iocoder.dashboard.framework.tracer.core.util.TracerUtils;
import cn.iocoder.dashboard.modules.system.controller.logger.vo.SysOperateLogCreateReqVO;
import cn.iocoder.dashboard.modules.system.enums.logger.SysOperateLogTypeEnum;
import cn.iocoder.dashboard.util.servlet.ServletUtils;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
@ -180,7 +180,7 @@ public class OperateLogAspect {
}
if (operateLogVO.getType() == null) {
RequestMethod requestMethod = obtainFirstMatchRequestMethod(obtainRequestMethod(joinPoint));
SysOperateLogTypeEnum operateLogType = convertOperateLogType(requestMethod);
OperateLogTypeEnum operateLogType = convertOperateLogType(requestMethod);
operateLogVO.setType(operateLogType != null ? operateLogType.getType() : null);
}
// content 和 exts 属性
@ -275,21 +275,21 @@ public class OperateLogAspect {
return requestMethods[0];
}
private static SysOperateLogTypeEnum convertOperateLogType(RequestMethod requestMethod) {
private static OperateLogTypeEnum convertOperateLogType(RequestMethod requestMethod) {
if (requestMethod == null) {
return null;
}
switch (requestMethod) {
case GET:
return SysOperateLogTypeEnum.GET;
return OperateLogTypeEnum.GET;
case POST:
return SysOperateLogTypeEnum.CREATE;
return OperateLogTypeEnum.CREATE;
case PUT:
return SysOperateLogTypeEnum.UPDATE;
return OperateLogTypeEnum.UPDATE;
case DELETE:
return SysOperateLogTypeEnum.DELETE;
return OperateLogTypeEnum.DELETE;
default:
return SysOperateLogTypeEnum.OTHER;
return OperateLogTypeEnum.OTHER;
}
}

View File

@ -1,4 +1,4 @@
package cn.iocoder.dashboard.modules.system.enums.logger;
package cn.iocoder.dashboard.framework.logger.operatelog.core.enums;
import cn.iocoder.dashboard.framework.logger.operatelog.core.annotations.OperateLog;
import lombok.AllArgsConstructor;
@ -11,7 +11,7 @@ import lombok.Getter;
*/
@Getter
@AllArgsConstructor
public enum SysOperateLogTypeEnum {
public enum OperateLogTypeEnum {
/**
* 查询

View File

@ -0,0 +1,24 @@
package cn.iocoder.dashboard.framework.mybatis.core.mapper;
import cn.iocoder.dashboard.common.pojo.PageParam;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.framework.mybatis.core.util.MyBatisUtils;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.apache.ibatis.annotations.Param;
/**
* 在 MyBatis Plus 的 BaseMapper 的基础上拓展,提供更多的能力
*/
public interface BaseMapperX<T> extends BaseMapper<T> {
default PageResult<T> selectPage(PageParam pageParam, @Param("ew") Wrapper<T> queryWrapper) {
// MyBatis Plus 查询
IPage<T> mpPage = MyBatisUtils.buildPage(pageParam);
selectPage(mpPage, queryWrapper);
// 转换返回
return new PageResult<>(mpPage.getRecords(), mpPage.getTotal());
}
}

View File

@ -54,7 +54,6 @@ public class SysAuthController {
@ApiOperation("获取登陆用户的权限信息")
@GetMapping("/get-permission-info")
@OperateLog
public CommonResult<SysAuthPermissionInfoRespVO> getPermissionInfo() {
// 获得用户信息
SysUserDO user = userService.getUser(getLoginUserId());

View File

@ -1,2 +1,2 @@
### 请求 /captcha/get-image 接口 => 成功
GET {{baseUrl}}/captcha/get-image
GET {{baseUrl}}/system/captcha/get-image

View File

@ -23,7 +23,7 @@ public class SysCaptchaController {
@ApiOperation("生成图片验证码")
@GetMapping("/get-image")
private CommonResult<SysCaptchaImageRespVO> getCaptchaImage() {
public CommonResult<SysCaptchaImageRespVO> getCaptchaImage() {
return success(captchaService.getCaptchaImage());
}

View File

@ -0,0 +1,3 @@
### 请求 /system/operate-log/demo 接口 => 成功
GET {{baseUrl}}/system/operate-log/demo
Authorization: Bearer {{token}}

View File

@ -0,0 +1,86 @@
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.logger.operatelog.core.annotations.OperateLog;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.util.OperateLogUtils;
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;
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.modules.system.service.logger.SysOperateLogService;
import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
import cn.iocoder.dashboard.util.collection.CollectionUtils;
import cn.iocoder.dashboard.util.collection.MapUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
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;
@Api(tags = "操作日志 API")
@RestController
@RequestMapping("/system/operate-log")
public class SysOperateLogController {
@Resource
private SysOperateLogService operateLogService;
@Resource
private SysUserService userService;
@ApiOperation("示例")
@OperateLog(type = OperateLogTypeEnum.OTHER)
@GetMapping("/demo")
public CommonResult<Boolean> demo() {
// 这里可以调用业务逻辑
// 补全操作日志的明细
OperateLogUtils.setContent("将编号 1 的数据xxx 字段修改成了 yyyy");
OperateLogUtils.addExt("orderId", 1);
// 响应
return success(true);
}
@ApiOperation("查看操作日志分页列表")
@GetMapping("/page")
// @PreAuthorize("@ss.hasPermi('system:operate-log:query')")
public CommonResult<PageResult<SysOperateLogRespVO>> pageOperateLog(@Validated SysOperateLogPageReqVO reqVO) {
PageResult<SysOperateLogDO> pageResult = operateLogService.pageOperateLog(reqVO);
// 获得拼接需要的数据
Collection<Long> userIds = CollectionUtils.convertList(pageResult.getList(), SysOperateLogDO::getUserId);
Map<Long, SysUserDO> userMap = userService.getUserMap(userIds);
// 拼接数据
List<SysOperateLogRespVO> list = new ArrayList<>(pageResult.getList().size());
pageResult.getList().forEach(operateLog -> {
SysOperateLogRespVO respVO = SysOperateLogConvert.INSTANCE.convert(operateLog);
list.add(respVO);
// 拼接用户信息
MapUtils.findAndThen(userMap, operateLog.getUserId(), user -> respVO.setUserNickname(user.getNickname()));
});
return success(new PageResult<>(list, pageResult.getTotal()));
}
// @Log(title = "操作日志", businessType = BusinessType.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, "操作日志");
// }
}

View File

@ -1 +0,0 @@
package cn.iocoder.dashboard.modules.system.controller.logger;

View File

@ -6,6 +6,7 @@ import lombok.Data;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.util.Date;
import java.util.Map;
/**
* 操作日志 Base VO提供给添加、修改、详细的子 VO 使用
@ -30,10 +31,16 @@ public class SysOperateLogBaseVO {
@NotEmpty(message = "操作名")
private String name;
@ApiModelProperty(value = "操作分类", required = true, example = "操作分类", notes = "参见 SysOperateLogTypeEnum 枚举类")
@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;

View File

@ -0,0 +1,39 @@
package cn.iocoder.dashboard.modules.system.controller.logger.vo;
import cn.iocoder.dashboard.common.pojo.PageParam;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
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
@EqualsAndHashCode(callSuper = true)
public class SysOperateLogPageReqVO extends PageParam {
@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

@ -0,0 +1,21 @@
package cn.iocoder.dashboard.modules.system.controller.logger.vo;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@ApiModel("操作日志 Response VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class SysOperateLogRespVO extends SysOperateLogBaseVO {
@ApiModelProperty(value = "日志编号", required = true, example = "1024")
private Long id;
@ApiModelProperty(value = "用户昵称", required = true, example = "芋艿")
private String userNickname;
}

View File

@ -1,6 +1,8 @@
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.SysOperateLogRespVO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
import org.mapstruct.Mapper;
import org.mapstruct.factory.Mappers;
@ -12,4 +14,8 @@ public interface SysOperateLogConvert {
SysOperateLogDO convert(SysOperateLogCreateReqVO bean);
PageResult<SysOperateLogRespVO> convertPage(PageResult<SysOperateLogDO> page);
SysOperateLogRespVO convert(SysOperateLogDO bean);
}

View File

@ -1,9 +1,30 @@
package cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger;
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.SysOperateLogPageReqVO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import java.util.Collection;
@Mapper
public interface SysOperateLogMapper extends BaseMapper<SysOperateLogDO> {
public interface SysOperateLogMapper extends BaseMapperX<SysOperateLogDO> {
default PageResult<SysOperateLogDO> selectPage(SysOperateLogPageReqVO 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());
}
return selectPage(reqVO, query);
}
}

View File

@ -45,5 +45,9 @@ public interface SysUserMapper extends BaseMapper<SysUserDO> {
.inIfPresent("dept_id", deptIds));
}
default List<SysUserDO> selectListByNickname(String nickname) {
return selectList(new QueryWrapperX<SysUserDO>().like("nickname", nickname));
}
}

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.modules.system.enums.logger.SysOperateLogTypeEnum;
import cn.iocoder.dashboard.framework.logger.operatelog.core.enums.OperateLogTypeEnum;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
@ -62,22 +62,18 @@ public class SysOperateLogDO extends BaseDO {
/**
* 操作分类
*
* 枚举 {@link SysOperateLogTypeEnum}
* 枚举 {@link OperateLogTypeEnum}
*/
@TableField("operate_type")
private Integer type;
/**
* 操作内容,记录整个操作的明细
* 例如说,修改编号为 1 的用户信息,将性别从男改成女,将姓名从芋道改成源码。
*
* TODO 预留字段
*/
private String content;
/**
* 拓展字段,有些复杂的业务,需要记录一些字段
* 例如说,记录订单编号,则可以添加 key 为 "orderId"value 为订单编号
*
* TODO 预留字段
*/
@TableField(typeHandler = FastjsonTypeHandler.class)
private Map<String, Object> exts;

View File

@ -1,9 +1,21 @@
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.SysOperateLogPageReqVO;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO;
/**
* 操作日志 Service 接口
*/
public interface SysOperateLogService extends OperateLogFrameworkService {
/**
* 获得操作日志分页列表
*
* @param reqVO 分页条件
* @return 操作日志分页列表
*/
PageResult<SysOperateLogDO> pageOperateLog(SysOperateLogPageReqVO reqVO);
}

View File

@ -1,18 +1,27 @@
package cn.iocoder.dashboard.modules.system.service.logger.impl;
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.SysOperateLogPageReqVO;
import cn.iocoder.dashboard.modules.system.convert.logger.SysOperateLogConvert;
import cn.iocoder.dashboard.modules.system.dal.mysql.dao.logger.SysOperateLogMapper;
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.modules.system.service.logger.SysOperateLogService;
import cn.iocoder.dashboard.modules.system.service.user.SysUserService;
import cn.iocoder.dashboard.util.string.StrUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.Collection;
import static cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.logger.SysOperateLogDO.*;
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;
import static cn.iocoder.dashboard.util.collection.CollectionUtils.convertSet;
@Service
@Slf4j
@ -21,6 +30,9 @@ public class SysOperateLogServiceImpl implements SysOperateLogService {
@Resource
private SysOperateLogMapper operateLogMapper;
@Resource
private SysUserService userService;
@Override
@Async
public void createOperateLogAsync(SysOperateLogCreateReqVO reqVO) {
@ -35,4 +47,18 @@ public class SysOperateLogServiceImpl implements SysOperateLogService {
}
}
@Override
public PageResult<SysOperateLogDO> pageOperateLog(SysOperateLogPageReqVO reqVO) {
// 处理基于用户昵称的查询
Collection<Long> userIds = null;
if (StrUtil.isNotEmpty(reqVO.getUserNickname())) {
userIds = convertSet(userService.listUsersByNickname(reqVO.getUserNickname()), SysUserDO::getId);
if (CollUtil.isEmpty(userIds)) {
return PageResult.empty();
}
}
// 查询分页
return operateLogMapper.selectPage(reqVO, userIds);
}
}

View File

@ -1,10 +1,15 @@
package cn.iocoder.dashboard.modules.system.service.user;
import cn.hutool.core.collection.CollUtil;
import cn.iocoder.dashboard.common.pojo.PageResult;
import cn.iocoder.dashboard.modules.system.controller.user.vo.user.*;
import cn.iocoder.dashboard.modules.system.dal.mysql.dataobject.user.SysUserDO;
import cn.iocoder.dashboard.util.collection.CollectionUtils;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* 用户 Service 接口
@ -45,6 +50,35 @@ public interface SysUserService {
*/
List<SysUserDO> listUsers(SysUserExportReqVO reqVO);
/**
* 获得用户列表
*
* @param ids 用户编号数组
* @return 用户列表
*/
List<SysUserDO> listUsers(Collection<Long> ids);
/**
* 获得用户 Map
*
* @param ids 用户编号数组
* @return 用户 Map
*/
default Map<Long, SysUserDO> getUserMap(Collection<Long> ids) {
if (CollUtil.isEmpty(ids)) {
return new HashMap<>();
}
return CollectionUtils.convertMap(listUsers(ids), SysUserDO::getId);
}
/**
* 获得用户列表,基于昵称模糊匹配
*
* @param nickname 昵称
* @return 用户列表
*/
List<SysUserDO> listUsersByNickname(String nickname);
/**
* 创建用户
*

View File

@ -83,6 +83,16 @@ public class SysUserServiceImpl implements SysUserService {
return userMapper.selectList(reqVO, this.getDeptCondition(reqVO.getDeptId()));
}
@Override
public List<SysUserDO> listUsers(Collection<Long> ids) {
return userMapper.selectBatchIds(ids);
}
@Override
public List<SysUserDO> listUsersByNickname(String nickname) {
return userMapper.selectListByNickname(nickname);
}
/**
* 获得部门条件:查询指定部门的子部门编号们,包括自身
*