📖 code review:操作日志的实现
This commit is contained in:
parent
82a25474f6
commit
5de6a8bd23
|
@ -46,9 +46,10 @@
|
||||||
<groupId>com.google.guava</groupId>
|
<groupId>com.google.guava</groupId>
|
||||||
<artifactId>guava</artifactId>
|
<artifactId>guava</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- Springboot-注解-通用操作日志组件 -->
|
|
||||||
<!-- 此组件解决的问题是: 「谁」在「什么时间」对「什么」做了「什么事」 -->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
|
<!-- Spring Boot 通用操作日志组件,基于注解实现 -->
|
||||||
|
<!-- 此组件解决的问题是:「谁」在「什么时间」对「什么」做了「什么事」 -->
|
||||||
<groupId>io.github.mouzt</groupId>
|
<groupId>io.github.mouzt</groupId>
|
||||||
<artifactId>bizlog-sdk</artifactId>
|
<artifactId>bizlog-sdk</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
|
@ -5,6 +5,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
@AutoConfiguration
|
@AutoConfiguration
|
||||||
public class YudaoOperateLogAutoConfiguration {
|
public class YudaoOperateLogAutoConfiguration {
|
||||||
|
|
||||||
|
// TODO @puhui999:这个是不是留着哈?因为老版本还是会留着一段时间的
|
||||||
//@Bean
|
//@Bean
|
||||||
//public OperateLogAspect operateLogAspect() {
|
//public OperateLogAspect operateLogAspect() {
|
||||||
// return new OperateLogAspect();
|
// return new OperateLogAspect();
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.springframework.boot.autoconfigure.AutoConfiguration;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Primary;
|
import org.springframework.context.annotation.Primary;
|
||||||
|
|
||||||
|
// TODO @puhui999:思考了下,为了减少 starter 数量,在 security 组件里,增加一个 core/operatelog 包,然后 YudaoOperateLogV2Configuration 搞一个过去;
|
||||||
/**
|
/**
|
||||||
* mzt-biz-log 配置类
|
* mzt-biz-log 配置类
|
||||||
*
|
*
|
||||||
|
|
|
@ -44,6 +44,7 @@ import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeC
|
||||||
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
|
import static cn.iocoder.yudao.framework.common.exception.enums.GlobalErrorCodeConstants.SUCCESS;
|
||||||
import static cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants.*;
|
import static cn.iocoder.yudao.framework.operatelogv2.core.enums.OperateLogV2Constants.*;
|
||||||
|
|
||||||
|
// TODO @puhui999:这个类,是不是可以删除哈;简化简化
|
||||||
/**
|
/**
|
||||||
* 拦截使用 @Operation 注解, 获取操作类型、开始时间、持续时间、方法相关信息、执行结果等信息
|
* 拦截使用 @Operation 注解, 获取操作类型、开始时间、持续时间、方法相关信息、执行结果等信息
|
||||||
* 对 mzt-biz-log 日志信息进行增强
|
* 对 mzt-biz-log 日志信息进行增强
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cn.iocoder.yudao.framework.operatelogv2.core.enums;
|
package cn.iocoder.yudao.framework.operatelogv2.core.enums;
|
||||||
|
|
||||||
|
// TODO @puhui999:这个类,是不是可以删除哈;
|
||||||
/**
|
/**
|
||||||
* 操作日志常量接口
|
* 操作日志常量接口
|
||||||
*
|
*
|
||||||
|
|
|
@ -1 +0,0 @@
|
||||||
package cn.iocoder.yudao.framework.operatelogv2.core;
|
|
|
@ -23,16 +23,17 @@ public class ILogRecordServiceImpl implements ILogRecordService {
|
||||||
public void record(LogRecord logRecord) {
|
public void record(LogRecord logRecord) {
|
||||||
OperateLogV2Aspect.setContent(logRecord); // 操作日志
|
OperateLogV2Aspect.setContent(logRecord); // 操作日志
|
||||||
OperateLogV2Aspect.addExtra(LogRecordContext.getVariables()); // 扩展信息
|
OperateLogV2Aspect.addExtra(LogRecordContext.getVariables()); // 扩展信息
|
||||||
|
// TODO @puhui999:这里是不是调用 operateLogApi 进行记录哈
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<LogRecord> queryLog(String bizNo, String type) {
|
public List<LogRecord> queryLog(String bizNo, String type) {
|
||||||
return Collections.emptyList();
|
throw new UnsupportedOperationException("不支持该操作,请使用 OperateLogApi 查询!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<LogRecord> queryLogByBizNo(String bizNo, String type, String subType) {
|
public List<LogRecord> queryLogByBizNo(String bizNo, String type, String subType) {
|
||||||
return Collections.emptyList();
|
throw new UnsupportedOperationException("不支持该操作,请使用 OperateLogApi 查询!");
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
// TODO @puhui999:这个最好每个模块自己弄哈,放这里有点怪可能
|
||||||
@Schema(description = "管理后台 - 操作日志分页 Request VO")
|
@Schema(description = "管理后台 - 操作日志分页 Request VO")
|
||||||
@Data
|
@Data
|
||||||
public class OperateLogV2PageReqVO extends PageParam {
|
public class OperateLogV2PageReqVO extends PageParam {
|
||||||
|
|
|
@ -8,6 +8,7 @@ import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY;
|
import static cn.iocoder.yudao.module.crm.enums.DictTypeConstants.CRM_CUSTOMER_INDUSTRY;
|
||||||
|
|
||||||
|
// TODO @puhui999:还是放在 core 包下哈;
|
||||||
/**
|
/**
|
||||||
* 自定义函数-通过行业编号获取行业信息
|
* 自定义函数-通过行业编号获取行业信息
|
||||||
*
|
*
|
||||||
|
@ -29,6 +30,7 @@ public class CrmIndustryParseFunction implements IParseFunction {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String apply(Object value) {
|
public String apply(Object value) {
|
||||||
|
// if (ObjUtil.isEmpty(value)) TODO @puhui999 可以直接替代哈;
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -37,10 +39,12 @@ public class CrmIndustryParseFunction implements IParseFunction {
|
||||||
}
|
}
|
||||||
|
|
||||||
// 获取行业信息
|
// 获取行业信息
|
||||||
|
// TODO @puhui999:这里可以不用 try catch 哇?
|
||||||
try {
|
try {
|
||||||
return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, value.toString());
|
return DictFrameworkUtils.getDictDataLabel(CRM_CUSTOMER_INDUSTRY, value.toString());
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
|
||||||
*/
|
*/
|
||||||
public class CrmPermissionUtils {
|
public class CrmPermissionUtils {
|
||||||
|
|
||||||
|
// TODO @puhui999:isCrmAdmin。换成这个名字;因为 validate 一般是参数校验,不符合抛出异常;一般是 isXXXValid 才会返回 true false
|
||||||
/**
|
/**
|
||||||
* 校验用户是否是 CRM 管理员
|
* 校验用户是否是 CRM 管理员
|
||||||
*
|
*
|
||||||
|
@ -21,6 +22,7 @@ public class CrmPermissionUtils {
|
||||||
return SingletonManager.getPermissionApi().hasAnyRoles(getUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode());
|
return SingletonManager.getPermissionApi().hasAnyRoles(getUserId(), CrmPermissionRoleCodeEnum.CRM_ADMIN.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:这个不需要哈,直接用原本的 SecuriyUtils 去拿更方便一些;
|
||||||
/**
|
/**
|
||||||
* 获得用户编号
|
* 获得用户编号
|
||||||
*
|
*
|
||||||
|
|
|
@ -68,6 +68,7 @@ public class CrmCustomerServiceImpl implements CrmCustomerService {
|
||||||
return customer.getId();
|
return customer.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:测试下,能不能打出用户数据的变更。啊哈,可以打完微信发我下;
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
@LogRecord(type = CRM_CUSTOMER, bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}")
|
@LogRecord(type = CRM_CUSTOMER, bizNo = "{{#updateReqVO.id}}", success = "更新了客户{_DIFF{#updateReqVO}}")
|
||||||
|
|
|
@ -90,6 +90,7 @@ public class CrmPermissionServiceImpl implements CrmPermissionService {
|
||||||
CrmPermissionDO oldPermission = crmPermissionMapper.selectByBizTypeAndBizIdByUserId(
|
CrmPermissionDO oldPermission = crmPermissionMapper.selectByBizTypeAndBizIdByUserId(
|
||||||
transferReqBO.getBizType(), transferReqBO.getBizId(), transferReqBO.getUserId());
|
transferReqBO.getBizType(), transferReqBO.getBizId(), transferReqBO.getUserId());
|
||||||
String bizTypeName = CrmBizTypeEnum.getNameByType(transferReqBO.getBizType());
|
String bizTypeName = CrmBizTypeEnum.getNameByType(transferReqBO.getBizType());
|
||||||
|
// TODO @puhui999:是不是并且? 不是拥有者,并且不是超管
|
||||||
if (oldPermission == null || !isOwner(oldPermission.getLevel()) || !CrmPermissionUtils.validateAdminUser()) {
|
if (oldPermission == null || !isOwner(oldPermission.getLevel()) || !CrmPermissionUtils.validateAdminUser()) {
|
||||||
throw exception(CRM_PERMISSION_DENIED, bizTypeName);
|
throw exception(CRM_PERMISSION_DENIED, bizTypeName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -98,6 +98,7 @@ public class CrmQueryWrapperUtils {
|
||||||
private static class SingletonManager {
|
private static class SingletonManager {
|
||||||
|
|
||||||
private static final AdminUserApi ADMIN_USER_API = SpringUtil.getBean(AdminUserApi.class);
|
private static final AdminUserApi ADMIN_USER_API = SpringUtil.getBean(AdminUserApi.class);
|
||||||
|
|
||||||
private static final MybatisPlusJoinProperties MYBATIS_PLUS_JOIN_PROPERTIES = SpringUtil.getBean(MybatisPlusJoinProperties.class);
|
private static final MybatisPlusJoinProperties MYBATIS_PLUS_JOIN_PROPERTIES = SpringUtil.getBean(MybatisPlusJoinProperties.class);
|
||||||
|
|
||||||
public static AdminUserApi getAdminUserApi() {
|
public static AdminUserApi getAdminUserApi() {
|
||||||
|
|
|
@ -75,10 +75,9 @@ public class AppActivityController {
|
||||||
if (CollUtil.isEmpty(spuIds)) {
|
if (CollUtil.isEmpty(spuIds)) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalDateTime now = LocalDateTime.now();
|
|
||||||
// 获取开启的且开始的且没有结束的活动
|
// 获取开启的且开始的且没有结束的活动
|
||||||
List<AppActivityRespVO> activityList = new ArrayList<>();
|
List<AppActivityRespVO> activityList = new ArrayList<>();
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
// 1. 拼团活动
|
// 1. 拼团活动
|
||||||
getCombinationActivities(spuIds, now, activityList);
|
getCombinationActivities(spuIds, now, activityList);
|
||||||
// 2. 秒杀活动
|
// 2. 秒杀活动
|
||||||
|
@ -99,6 +98,7 @@ public class AppActivityController {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:AppActivityRespVO 搞个构造方法,写起来更方便一些;这样后续万一加个属性,也可以处理下哈;
|
||||||
combinationActivities.forEach(item -> {
|
combinationActivities.forEach(item -> {
|
||||||
activityList.add(new AppActivityRespVO().setId(item.getId())
|
activityList.add(new AppActivityRespVO().setId(item.getId())
|
||||||
.setType(PromotionTypeEnum.COMBINATION_ACTIVITY.getType()).setName(item.getName())
|
.setType(PromotionTypeEnum.COMBINATION_ACTIVITY.getType()).setName(item.getName())
|
||||||
|
@ -144,11 +144,9 @@ public class AppActivityController {
|
||||||
List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId(
|
List<DiscountProductDO> products = discountActivityService.getDiscountProductsByActivityId(
|
||||||
convertSet(discountActivities, DiscountActivityDO::getId));
|
convertSet(discountActivities, DiscountActivityDO::getId));
|
||||||
Map<Long, Long> productMap = convertMap(products, DiscountProductDO::getActivityId, DiscountProductDO::getSpuId);
|
Map<Long, Long> productMap = convertMap(products, DiscountProductDO::getActivityId, DiscountProductDO::getSpuId);
|
||||||
discountActivities.forEach(item -> {
|
discountActivities.forEach(item -> activityList.add(new AppActivityRespVO().setId(item.getId())
|
||||||
activityList.add(new AppActivityRespVO().setId(item.getId())
|
|
||||||
.setType(PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()).setName(item.getName())
|
.setType(PromotionTypeEnum.DISCOUNT_ACTIVITY.getType()).setName(item.getName())
|
||||||
.setSpuId(productMap.get(item.getId())).setStartTime(item.getStartTime()).setEndTime(item.getEndTime()));
|
.setSpuId(productMap.get(item.getId())).setStartTime(item.getStartTime()).setEndTime(item.getEndTime())));
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void getRewardActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
|
private void getRewardActivities(Collection<Long> spuIds, LocalDateTime now, List<AppActivityRespVO> activityList) {
|
||||||
|
|
|
@ -98,6 +98,7 @@ public interface DiscountActivityService {
|
||||||
* @param dateTime 当前日期时间
|
* @param dateTime 当前日期时间
|
||||||
* @return 折扣活动列表
|
* @return 折扣活动列表
|
||||||
*/
|
*/
|
||||||
List<DiscountActivityDO> getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
|
List<DiscountActivityDO> getDiscountActivityBySpuIdsAndStatusAndDateTimeLt(
|
||||||
|
Collection<Long> spuIds, Integer status, LocalDateTime dateTime);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -59,13 +59,12 @@ public class OperateLogApiImpl implements OperateLogApi {
|
||||||
return BeanUtils.toBean(operateLogPage, OperateLogV2RespDTO.class).setList(setUserInfo(operateLogPage.getList(), userList));
|
return BeanUtils.toBean(operateLogPage, OperateLogV2RespDTO.class).setList(setUserInfo(operateLogPage.getList(), userList));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:这种 convert 还是放到 convert 类里,
|
||||||
private static List<OperateLogV2RespDTO> setUserInfo(List<OperateLogV2DO> logList, List<AdminUserDO> userList) {
|
private static List<OperateLogV2RespDTO> setUserInfo(List<OperateLogV2DO> logList, List<AdminUserDO> userList) {
|
||||||
Map<Long, AdminUserDO> userMap = convertMap(userList, AdminUserDO::getId);
|
Map<Long, AdminUserDO> userMap = convertMap(userList, AdminUserDO::getId);
|
||||||
return convertList(logList, item -> {
|
return convertList(logList, item -> {
|
||||||
OperateLogV2RespDTO respDTO = BeanUtils.toBean(item, OperateLogV2RespDTO.class);
|
OperateLogV2RespDTO respDTO = BeanUtils.toBean(item, OperateLogV2RespDTO.class);
|
||||||
findAndThen(userMap, item.getUserId(), user -> {
|
findAndThen(userMap, item.getUserId(), user -> respDTO.setUserName(user.getNickname()));
|
||||||
respDTO.setUserName(user.getNickname());
|
|
||||||
});
|
|
||||||
return respDTO;
|
return respDTO;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -70,6 +70,7 @@ public class OperateLogV2DO extends BaseDO {
|
||||||
* 操作模块业务编号
|
* 操作模块业务编号
|
||||||
*/
|
*/
|
||||||
private Long bizId;
|
private Long bizId;
|
||||||
|
// TODO @puhui999:content 改成 action,extra 换成 String。注释就直接用 mzt,和它完全对应好了。
|
||||||
/**
|
/**
|
||||||
* 操作内容,记录整个操作的明细
|
* 操作内容,记录整个操作的明细
|
||||||
*
|
*
|
||||||
|
@ -83,6 +84,7 @@ public class OperateLogV2DO extends BaseDO {
|
||||||
*/
|
*/
|
||||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||||
private Map<String, Object> extra;
|
private Map<String, Object> extra;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 请求方法名
|
* 请求方法名
|
||||||
*/
|
*/
|
||||||
|
@ -100,6 +102,7 @@ public class OperateLogV2DO extends BaseDO {
|
||||||
*/
|
*/
|
||||||
private String userAgent;
|
private String userAgent;
|
||||||
|
|
||||||
|
// TODO @puhui999:微信已经讨论,下面的字段都不要哈;
|
||||||
/**
|
/**
|
||||||
* Java 方法名
|
* Java 方法名
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -27,6 +27,7 @@ public class AdminUserParseFunction implements IParseFunction {
|
||||||
return "getAdminUserById";
|
return "getAdminUserById";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO @puhui999:这个方法的实现优化下哈;
|
||||||
@Override
|
@Override
|
||||||
public String apply(Object value) {
|
public String apply(Object value) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
|
|
|
@ -6,6 +6,7 @@ import com.mzt.logapi.service.IParseFunction;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
// TODO @puhui999:还是放在 core 包下哈;
|
||||||
/**
|
/**
|
||||||
* 自定义函数-通过区域编号获取区域信息
|
* 自定义函数-通过区域编号获取区域信息
|
||||||
*
|
*
|
||||||
|
@ -36,4 +37,5 @@ public class AreaParseFunction implements IParseFunction {
|
||||||
|
|
||||||
return AreaUtils.format(Integer.parseInt(value.toString()));
|
return AreaUtils.format(Integer.parseInt(value.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,17 +79,11 @@ mybatis-plus:
|
||||||
password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成
|
password: XDV71a+xqStEA3WH # 加解密的秘钥,可使用 https://www.imaegoo.com/2020/aes-key-generator/ 网站生成
|
||||||
|
|
||||||
mybatis-plus-join:
|
mybatis-plus-join:
|
||||||
#是否打印 mybatis plus join banner 默认true
|
banner: false # 是否打印 mybatis plus join banner,默认true
|
||||||
banner: false
|
sub-table-logic: true # 全局启用副表逻辑删除,默认true。关闭后关联查询不会加副表逻辑删除
|
||||||
#全局启用副表逻辑删除(默认true) 关闭后关联查询不会加副表逻辑删除
|
ms-cache: true # 拦截器MappedStatement缓存,默认 true
|
||||||
sub-table-logic: true
|
table-alias: t # 表别名(默认 t)
|
||||||
#拦截器MappedStatement缓存(默认true)
|
logic-del-type: on # 副表逻辑删除条件的位置,支持 WHERE、ON,默认 ON
|
||||||
ms-cache: true
|
|
||||||
#表别名(默认 t)
|
|
||||||
table-alias: t
|
|
||||||
#副表逻辑删除条件的位置,支持where、on
|
|
||||||
#默认ON (1.4.7.2及之前版本默认为where)
|
|
||||||
logic-del-type: on
|
|
||||||
|
|
||||||
# Spring Data Redis 配置
|
# Spring Data Redis 配置
|
||||||
spring:
|
spring:
|
||||||
|
|
Loading…
Reference in New Issue