package com.shangwei.system.service.impl;
import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.shangwei.common.core.exception.ServiceException;
import com.shangwei.common.core.utils.StreamUtils;
import com.shangwei.common.core.utils.StringUtils;
import com.shangwei.common.core.utils.ValidatorUtils;
import com.shangwei.common.core.validate.AddGroup;
import com.shangwei.common.mybatis.core.page.PageQuery;
import com.shangwei.common.mybatis.core.page.TableDataInfo;
import com.shangwei.common.mybatis.interceptor.MybatisTenantContext;
import com.shangwei.system.api.domain.bo.LogRecordsBo;
import com.shangwei.system.domain.LogModule;
import com.shangwei.system.domain.LogPoint;
import com.shangwei.system.domain.LogRecords;
import com.shangwei.system.domain.bo.LogModuleBo;
import com.shangwei.system.domain.bo.LogPointBo;
import com.shangwei.system.mapper.LogModuleMapper;
import com.shangwei.system.mapper.LogPointMapper;
import com.shangwei.system.mapper.LogRecordMapper;
import com.shangwei.system.service.ILogRecordService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* 日志实现类
*
* @author xyl
*/
@Slf4j
@RequiredArgsConstructor
@Service
public class LogRecordServiceImpl implements ILogRecordService {
private final LogRecordMapper baseMapper;
private final LogModuleMapper moduleMapper;
private final LogPointMapper pointMapper;
private final ConcurrentMap<Long, ConcurrentMap<Long, LogModuleBo>> cache = new ConcurrentHashMap<>();
@Override
public void save(LogRecordsBo logRecordBo) {
ValidatorUtils.validate(logRecordBo, AddGroup.class);
LogModule module = BeanUtil.copyProperties(logRecordBo, LogModule.class);
LogPoint point = BeanUtil.copyProperties(logRecordBo, LogPoint.class);
LogRecords record = BeanUtil.copyProperties(logRecordBo, LogRecords.class);
Long deptId = record.getOprDeptId();
try {
boolean isMoudleAdd = checkModule(module, deptId);
point.setModuleId(module.getId());
boolean isPointAdd = checkPoint(point, deptId);
record.setModuleId(module.getId());
record.setPointId(point.getId());
baseMapper.insert(record);
if (isMoudleAdd) {
processCacheByModule(deptId, module);
}
if (isPointAdd) {
processCacheByPoint(deptId, point);
}
} catch (NullPointerException | ServiceException e) {
e.printStackTrace();
} finally {
log.info("save log end");
}
}
@Override
public void loadingCache() {
try {
MybatisTenantContext.set(true);
List<LogRecords> records = baseMapper.loadCache();
if (!records.isEmpty()) {
List<LogModule> modules = moduleMapper.selectList();
List<LogPoint> points = pointMapper.selectList();
//数据分组
Map<Long, LogModule> groupsByModules = StreamUtils.toIdentityMap(modules, LogModule::getId);
Map<Long, LogPoint> groupsByPoints = StreamUtils.toIdentityMap(points, LogPoint::getId);
Map<Long, List<LogRecords>> groupsByRecords = StreamUtils.groupByKey(records, LogRecords::getOprDeptId);
//按部门遍历
for (Long deptId : groupsByRecords.keySet()) {
ConcurrentMap<Long, LogModuleBo> cacheByModule = new ConcurrentHashMap<>(1);
//获取部门的模块-节点
List<LogRecords> logRecordsByDeptId = groupsByRecords.get(deptId);
//进一步用模块id分组
Map<Long, List<LogRecords>> groupsByModuleWithDeptId = StreamUtils.groupByKey(logRecordsByDeptId, LogRecords::getModuleId);
//按模块遍历
for (Long moduleId : groupsByModuleWithDeptId.keySet()) {
List<LogRecords> byPoints = groupsByModuleWithDeptId.get(moduleId);
//模块存在就转换数据到cache
LogModule module = groupsByModules.get(moduleId);
if (Objects.nonNull(module)) {
LogModuleBo moduleBo = BeanUtil.copyProperties(module, LogModuleBo.class);
for (LogRecords byPoint : byPoints) {
LogPoint point = groupsByPoints.get(byPoint.getPointId());
if (Objects.nonNull(point)) {
LogPointBo pointBo = BeanUtil.copyProperties(point, LogPointBo.class);
moduleBo.addPoints(pointBo);
}
}
cacheByModule.put(moduleId, moduleBo);
}
}
cache.put(deptId, cacheByModule);
}
}
} finally {
MybatisTenantContext.clear();
}
log.info("加载缓存完成");
}
@Override
public Object readCache(Long deptId) {
if (Objects.isNull(deptId)) {
return null;
}
return cache.containsKey(deptId) ? cache.get(deptId).values() : null;
}
@Override
public TableDataInfo<LogRecordsBo> selectPageList(LogRecordsBo log, PageQuery pageQuery) {
Map<String, Object> params = log.getParams();
Object keyword = params.get("keyword");
boolean hasKeyword = Objects.nonNull(keyword) && StringUtils.isNotBlank(String.valueOf(keyword));
LambdaQueryWrapper<LogRecords> lqw = new LambdaQueryWrapper<LogRecords>()
.eq(Objects.nonNull(log.getOprDeptId()), LogRecords::getOprDeptId, log.getOprDeptId())
.eq(Objects.nonNull(log.getPointId()), LogRecords::getPointId, log.getPointId())
.eq(Objects.nonNull(log.getModuleId()), LogRecords::getModuleId, log.getModuleId())
.eq(StringUtils.isNotBlank(log.getBusinessType()), LogRecords::getBusinessType, log.getBusinessType())
.and(hasKeyword, wrapper -> wrapper.or().eq(hasKeyword, LogRecords::getOprIp, keyword)
.or().eq(hasKeyword, LogRecords::getOprName, keyword))
.between(params.get("beginTime") != null && params.get("endTime") != null,
LogRecords::getOprTime, params.get("beginTime"), params.get("endTime"));
if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
pageQuery.setOrderByColumn("opr_time");
pageQuery.setIsAsc("desc");
}
Page<LogRecordsBo> page = baseMapper.selectVoPage(pageQuery.build(), lqw, LogRecordsBo.class);
return TableDataInfo.build(page);
}
/**
* 新增节点到缓存
*
* @param oprDeptId 部门id
* @param point 节点
*/
private void processCacheByPoint(Long oprDeptId, LogPoint point) {
ConcurrentMap<Long, LogModuleBo> cacheByDept = cache.get(oprDeptId);
if (Objects.nonNull(cacheByDept)) {
LogModuleBo moduleBo = cacheByDept.get(point.getModuleId());
if (Objects.nonNull(moduleBo)) {
moduleBo.addPoints(BeanUtil.copyProperties(point, LogPointBo.class));
}
}
}
/**
* 新增模块到缓存
*
* @param oprDeptId 部门id
* @param module 模块
日志通过ApplicationEvent、Annotation、MQ实现公用逻辑
需积分: 0 191 浏览量
更新于2023-07-06
收藏 10KB 7Z 举报
在IT行业中,日志记录是系统开发不可或缺的一部分,它用于追踪程序运行状态,排查错误,以及性能监控。本文将深入探讨如何使用`ApplicationEvent`、注解和消息队列(MQ)来实现日志记录的公用逻辑。我们将重点关注Java日志的高级实践,涉及到的服务实现、接口设计、消息中间件的运用,以及相关的代码结构。
`ApplicationEvent`是Spring框架中的一个核心概念,它是事件驱动架构的一部分。当系统中发生某个重要事件时,可以通过创建并发布`ApplicationEvent`来通知其他关注此事件的组件。在日志记录场景中,我们可以定义自定义的事件类型,如`LogRecordingEvent`,每当需要记录日志时,就触发这个事件。这允许日志处理逻辑与业务逻辑解耦,提高了代码的可维护性和可扩展性。
接着,`ILogRecordService`很可能是日志服务的接口,它定义了日志记录的相关方法,如`recordLog()`。这个接口可以被多个模块或服务实现,具体记录日志的方式可以由实现类决定,例如写入文件、数据库或通过MQ发送。接口的设计使得日志服务的实现可以轻松替换,便于升级或优化。
`LogRecordServiceImpl`是`ILogRecordService`的具体实现。在实现中,可能会利用`ApplicationEventPublisher`来发布`LogRecordingEvent`,并将日志数据作为事件参数传递。同时,为了处理异步日志记录,可以考虑使用Spring的`@Async`注解,这样日志记录操作将在后台线程执行,不会阻塞主线程。
接下来,`mq`目录可能包含了与消息队列相关的配置和实现。消息队列(如RabbitMQ、Kafka或ActiveMQ)常用于日志收集,因为它能提供高并发、低延迟和可扩展性。日志数据可以被发送到MQ,然后由专门的日志分析或存储服务消费。这种方式特别适合大规模分布式系统的日志管理。
`common`目录可能包含了一些通用工具类或模型,比如日志对象的`LogBean`,它封装了日志的基本信息,如时间戳、级别、源、消息等。`api`目录可能包含对外提供的日志API接口,让其他服务能够方便地调用日志记录服务。`bean`目录可能包含Spring的Bean配置文件,定义了服务实例、事件监听器等。
通过`ApplicationEvent`、注解和消息队列,我们可以构建出一个灵活且高效的日志处理系统。这种设计不仅可以确保日志记录的实时性,还能降低系统复杂性,提高可扩展性。在实际项目中,还需要考虑日志的分类、过滤、归档等策略,以满足不同的监控和分析需求。

风起黄金梦
- 粉丝: 0
最新资源
- PLC控制系统抗干扰技术设计方案策略.doc
- 大数据时代下的城建档案信息资源利用.docx
- 局域网环境下网络安全技术的应用.docx
- 软件工程师考评表.doc
- 2017年4月自考计算机网络技术试题和答案.doc
- Nutanix-API-接口-Reference-NOS-v4.pdf
- 大数据助力党建工作智慧升级.docx
- 推动工业互联网+5G融合发展.docx
- 服装行业电子商务解决方案.doc
- 我国古玩行业现状:超五成玩家为中产阶级消费群集中在中段.docx
- GNSS数据采集与处理技术设计书.docx
- 南华大学操作系统期末复习资料PPT13级.ppt
- 区块链技术应用于支付清算领域研究.docx
- 教育系统移动信息化整体解决方案.doc
- 交通信号灯施工方案.doc
- ppt课件:信息化高科技人工智能工业机器人PPT模板.pptx