📖 code review:操作日志的实现

This commit is contained in:
YunaiV 2023-12-25 21:40:16 +08:00
parent 82a25474f6
commit 5de6a8bd23
20 changed files with 40 additions and 27 deletions

View File

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

View File

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

View File

@ -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 配置类
* *

View File

@ -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 日志信息进行增强

View File

@ -1,5 +1,6 @@
package cn.iocoder.yudao.framework.operatelogv2.core.enums; package cn.iocoder.yudao.framework.operatelogv2.core.enums;
// TODO @puhui999这个类是不是可以删除哈
/** /**
* 操作日志常量接口 * 操作日志常量接口
* *

View File

@ -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 查询!");
} }
} }

View File

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

View File

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

View File

@ -12,6 +12,7 @@ import cn.iocoder.yudao.module.system.api.permission.PermissionApi;
*/ */
public class CrmPermissionUtils { public class CrmPermissionUtils {
// TODO @puhui999isCrmAdmin换成这个名字因为 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 去拿更方便一些
/** /**
* 获得用户编号 * 获得用户编号
* *

View File

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

View File

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

View File

@ -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() {

View File

@ -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 @puhui999AppActivityRespVO 搞个构造方法写起来更方便一些这样后续万一加个属性也可以处理下哈
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) {

View File

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

View File

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

View File

@ -70,6 +70,7 @@ public class OperateLogV2DO extends BaseDO {
* 操作模块业务编号 * 操作模块业务编号
*/ */
private Long bizId; private Long bizId;
// TODO @puhui999content 改成 actionextra 换成 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 方法名
*/ */

View File

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

View File

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

View File

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