From 34981c30a78e8bbd7791131059a9210f9928b62c Mon Sep 17 00:00:00 2001
From: 刘光辉 <347230014@qq.com>
Date: 星期四, 17 九月 2026 09:24:09 +0800
Subject: [PATCH] Merge remote-tracking branch 'origin/master' into master
---
jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/impl/AuditQueryServiceImpl.java | 353 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 353 insertions(+), 0 deletions(-)
diff --git a/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/impl/AuditQueryServiceImpl.java b/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/impl/AuditQueryServiceImpl.java
new file mode 100644
index 0000000..1c193f3
--- /dev/null
+++ b/jnpf-biz-common/jnpf-biz-common-audit/src/main/java/jnpf/bizcommon/audit/service/impl/AuditQueryServiceImpl.java
@@ -0,0 +1,353 @@
+package jnpf.bizcommon.audit.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import jnpf.audit.AuditConsts;
+import jnpf.bizcommon.audit.entity.AuditEventEntity;
+import jnpf.bizcommon.audit.entity.model.AuditEventDetailVO;
+import jnpf.bizcommon.audit.entity.model.AuditEventListVO;
+import jnpf.bizcommon.audit.entity.model.AuditOperationGroupRow;
+import jnpf.bizcommon.audit.entity.model.AuditPageQuery;
+import jnpf.bizcommon.audit.mapper.AuditEventMapper;
+import jnpf.bizcommon.audit.mapper.AuditQueryMapper;
+import jnpf.bizcommon.audit.service.AuditFieldDiffViewService;
+import jnpf.bizcommon.audit.service.AuditFormRegistry;
+import jnpf.bizcommon.audit.service.AuditQueryService;
+import jnpf.bizcommon.audit.service.support.AuditQueryResponseSanitizer;
+import jnpf.bizcommon.audit.service.support.AuditEventCategories;
+import jnpf.base.vo.PageListVO;
+import jnpf.base.vo.PaginationVO;
+import jnpf.exception.DataException;
+import jnpf.util.JsonUtil;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.StringUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/** 瀹¤浜嬩欢鏌ヨ鏈嶅姟锛涘啓鍏ヤ晶瀹屾垚鐗╃悊鍚堝苟锛屾煡璇晶浠呮寜 operationId 缁勭粐灞曠ず鍏崇郴銆� */
+@Service
+public class AuditQueryServiceImpl implements AuditQueryService {
+
+ /** timeline 鍏ㄩ噺涓婇檺锛坰pec锛歀IMIT 500锛� */
+ private static final int TIMELINE_LIMIT = 500;
+ /** 鍒楄〃鍙笅鍙戝墠 3 鏉″瓙琛ㄦ爣棰� + 鎬绘暟鈥斺�斾繚鎸併�屽垪琛ㄤ笉鍚� extra 姝f枃銆嶇殑鏁忔劅闈㈢害瀹氥�� */
+ private static final int LIST_SUB_TITLE_LIMIT = 3;
+ /** 鍒嗛〉澶у皬涓婇檺锛圫tep 2 濂戠害锛氬己鍒� pageSize<=100锛� */
+ private static final long MAX_PAGE_SIZE = 100L;
+ private static final long DEFAULT_PAGE_SIZE = 20L;
+
+ @Autowired
+ private AuditQueryMapper auditQueryMapper;
+
+ @Autowired
+ private AuditEventMapper auditEventMapper;
+
+ @Autowired
+ private AuditFormRegistry auditFormRegistry;
+
+ @Autowired
+ private AuditFieldDiffViewService auditFieldDiffViewService;
+
+ @Override
+ public PageListVO<AuditEventListVO> page(AuditPageQuery query) {
+ long pageSize = query.getPageSize();
+ if (pageSize <= 0) {
+ pageSize = DEFAULT_PAGE_SIZE;
+ } else if (pageSize > MAX_PAGE_SIZE) {
+ pageSize = MAX_PAGE_SIZE;
+ }
+ long currentPage = query.getCurrentPage();
+ if (currentPage <= 0) {
+ currentPage = 1L;
+ }
+ // Codex 鎵规涓塧 Minor#3锛歄FFSET 婧㈠嚭闃叉姢鈥斺�攃urrentPage 浼犺秴澶у�硷紙濡� Long.MAX_VALUE锛夋椂
+ // (currentPage-1)*pageSize 浼� long 涔樻硶婧㈠嚭鎴愯礋鏁帮紝鎷艰繘 SQL LIMIT/OFFSET 璇箟鏈畾涔夈��
+ // Math.multiplyExact 鏄惧紡妫�娴嬫孩鍑猴紝鍛戒腑鍒欓檷绾т负绌洪〉锛坱otal 浠嶆寜鏉′欢姝e父杩斿洖锛屼笉鏌ユ槑缁嗛〉锛夈��
+ long offset;
+ boolean offsetOverflow;
+ try {
+ offset = Math.multiplyExact(currentPage - 1, pageSize);
+ offsetOverflow = false;
+ } catch (ArithmeticException ex) {
+ offset = 0L;
+ offsetOverflow = true;
+ }
+
+ QueryWrapper<AuditEventEntity> ew = buildWrapper(query);
+ long total = auditQueryMapper.countOperations(ew);
+ List<AuditEventListVO> list;
+ if (offsetOverflow) {
+ list = Collections.emptyList();
+ } else {
+ List<AuditOperationGroupRow> groups = auditQueryMapper.selectOperationPage(ew, offset, pageSize);
+ list = buildOperationRows(groups);
+ }
+
+ // 鍥炲啓鐢熸晥鍚庣殑鍒嗛〉鍙傛暟渚涜繑鍥炲寘瑁呰鍙栵紙瀵圭収 LimsBizLogController锛歅agination 鎵胯浇 total锛�
+ // JsonUtil.getJsonToBean 绐勫寲鎴� PaginationVO鈥斺�斿悓涓�鎯緥锛屼粎鎸埌 Service 灞備互璐村悎鏈换鍔�
+ // 瀛楅潰鎵ц鐨� Controller 绛惧悕锛�
+ query.setCurrentPage(currentPage);
+ query.setPageSize(pageSize);
+ query.setTotal(total);
+
+ PageListVO<AuditEventListVO> vo = new PageListVO<>();
+ vo.setList(list);
+ vo.setPagination(JsonUtil.getJsonToBean(query, PaginationVO.class));
+ return vo;
+ }
+
+ @Override
+ public AuditEventDetailVO detail(Long id) {
+ AuditEventEntity entity = auditEventMapper.selectById(id);
+ if (entity == null) {
+ throw new DataException("瀹¤浜嬩欢涓嶅瓨鍦細id=" + id);
+ }
+ return toDetailVo(entity);
+ }
+
+ @Override
+ public List<AuditEventListVO> timeline(String targetId) {
+ List<AuditOperationGroupRow> groups = groupRows(
+ auditQueryMapper.selectTimeline(targetId, TIMELINE_LIMIT));
+ // target_id 鍙睘浜庝笟鍔$洰鏍囪锛涚鍚嶇瓑鍏宠仈浜嬩欢浣跨敤鑷繁鐨� target_id锛岄渶鎸� operation_id 琛ユ煡銆�
+ return buildOperationRows(groups);
+ }
+
+ private List<AuditEventListVO> buildOperationRows(List<AuditOperationGroupRow> groups) {
+ if (groups.isEmpty()) {
+ return Collections.emptyList();
+ }
+ List<String> gids = new ArrayList<>(groups.size());
+ for (AuditOperationGroupRow group : groups) {
+ gids.add(group.getGid());
+ }
+ return buildOperationRows(groups, auditQueryMapper.selectByOperationGids(gids));
+ }
+
+ /** 灏嗗凡鐗╃悊鍚堝苟鐨勪簨浠舵寕鍒� BUSINESS 涓昏锛涜繖閲屼笉寰楀啀娆$粍鍚� fieldDiffs銆� */
+ private List<AuditEventListVO> buildOperationRows(List<AuditOperationGroupRow> groups,
+ List<AuditEventEntity> events) {
+ Map<String, List<AuditEventEntity>> eventsByGid = new LinkedHashMap<>();
+ for (AuditEventEntity event : events) {
+ String gid = operationGid(event);
+ eventsByGid.computeIfAbsent(gid, ignored -> new ArrayList<>()).add(event);
+ }
+
+ List<AuditEventListVO> result = new ArrayList<>(groups.size());
+ for (AuditOperationGroupRow group : groups) {
+ List<AuditEventEntity> related = eventsByGid.get(group.getGid());
+ if (related == null) {
+ continue;
+ }
+ AuditEventEntity business = null;
+ List<AuditEventListVO> signatures = new ArrayList<>(2);
+ for (AuditEventEntity event : related) {
+ if (AuditEventCategories.BUSINESS.equals(event.getEventCategory())) {
+ business = event;
+ } else if (AuditEventCategories.PRIMARY_SIGN.equals(event.getEventCategory())
+ || AuditEventCategories.REVIEW_SIGN.equals(event.getEventCategory())) {
+ signatures.add(toListVo(event));
+ }
+ }
+ if (business == null) {
+ continue;
+ }
+ AuditEventListVO main = toListVo(business);
+ main.setSubEvents(signatures);
+ main.setSigned(!signatures.isEmpty());
+ result.add(main);
+ }
+ return result;
+ }
+
+ private List<AuditOperationGroupRow> groupRows(List<AuditEventEntity> events) {
+ Map<String, AuditOperationGroupRow> groups = new LinkedHashMap<>();
+ for (AuditEventEntity event : events) {
+ String gid = operationGid(event);
+ AuditOperationGroupRow group = groups.get(gid);
+ if (group == null) {
+ group = new AuditOperationGroupRow();
+ group.setGid(gid);
+ group.setGrpTime(event.getEventTime());
+ groups.put(gid, group);
+ }
+ }
+ return new ArrayList<>(groups.values());
+ }
+
+ private String operationGid(AuditEventEntity event) {
+ return StringUtils.hasText(event.getOperationId()) ? event.getOperationId() : event.getClientEventId();
+ }
+
+ private QueryWrapper<AuditEventEntity> buildWrapper(AuditPageQuery query) {
+ QueryWrapper<AuditEventEntity> ew = new QueryWrapper<>();
+ if (query.getStartTime() != null) {
+ ew.ge("event_time", query.getStartTime());
+ }
+ if (query.getEndTime() != null) {
+ ew.le("event_time", query.getEndTime());
+ }
+ if (StringUtils.hasText(query.getOperatorName())) {
+ ew.like("operator_name", query.getOperatorName());
+ }
+ if (StringUtils.hasText(query.getAppName())) {
+ ew.eq("app_name", query.getAppName());
+ }
+ // Codex 鎵规涓塧 Important#1锛歜iz_module 鏄敤鎴疯瑙掔殑涓氬姟搴旂敤绛涢�夛紙app_name 灞� 0 鍥哄畾涓� jnpf-visualdev锛�
+ if (StringUtils.hasText(query.getBizModule())) {
+ ew.eq("biz_module", query.getBizModule());
+ }
+ if (StringUtils.hasText(query.getEventType())) {
+ ew.eq("event_type", query.getEventType());
+ }
+ if (StringUtils.hasText(query.getActionCode())) {
+ ew.eq("action_code", query.getActionCode());
+ }
+ if (StringUtils.hasText(query.getTargetTable())) {
+ ew.eq("target_table", query.getTargetTable());
+ }
+ if (StringUtils.hasText(query.getBizCode())) {
+ ew.eq("biz_code", query.getBizCode());
+ }
+ if (StringUtils.hasText(query.getBizType())) {
+ ew.eq("biz_type", query.getBizType());
+ }
+ if (StringUtils.hasText(query.getKeyword())) {
+ ew.like("field_diffs", query.getKeyword());
+ }
+ return ew;
+ }
+
+ private AuditEventListVO toListVo(AuditEventEntity e) {
+ AuditEventListVO vo = new AuditEventListVO();
+ vo.setId(e.getId());
+ vo.setOperationId(e.getOperationId());
+ vo.setClientEventId(e.getClientEventId());
+ vo.setEventTime(e.getEventTime());
+ vo.setTenantId(e.getTenantId());
+ vo.setOperatorId(e.getOperatorId());
+ vo.setOperatorName(e.getOperatorName());
+ vo.setOperatorOrgId(e.getOperatorOrgId());
+ vo.setAppName(e.getAppName());
+ vo.setBizModule(e.getBizModule());
+ vo.setIp(e.getIp());
+ vo.setIpRegion(e.getIpRegion());
+ vo.setBrowser(e.getBrowser());
+ vo.setOs(e.getOs());
+ vo.setRequestUri(e.getRequestUri());
+ vo.setEventType(e.getEventType());
+ if (AuditEventCategories.REVIEW_SIGN.equals(e.getEventCategory())) {
+ vo.setSignatureRole("REVIEW");
+ } else if (AuditEventCategories.PRIMARY_SIGN.equals(e.getEventCategory())) {
+ vo.setSignatureRole("PRIMARY");
+ }
+ vo.setActionCode(e.getActionCode());
+ vo.setActionLabel(e.getActionLabel());
+ vo.setSourceLayer(e.getSourceLayer());
+ vo.setTargetTable(e.getTargetTable());
+ vo.setTargetId(AuditQueryResponseSanitizer.hidesTargetId(e.getTargetTable())
+ ? null : e.getTargetId());
+ vo.setBizType(e.getBizType());
+ vo.setBizCode(e.getBizCode());
+ vo.setDiffCount(computeDiffCount(e.getFieldDiffs()));
+ vo.setReason(e.getReason());
+ vo.setRecordTitle(e.getRecordTitle());
+ vo.setEntryType(e.getEntryType());
+ vo.setEntryId(e.getEntryId());
+ vo.setEntryName(e.getEntryName());
+ vo.setCreatedAt(e.getCreatedAt());
+ // 瀛愪簨浠朵繚鐣欒嚜韬鍚嶆爣璁帮紱BUSINESS 涓昏浼氬湪缁勮鍚庢寜鍏宠仈绛惧悕閲嶆柊璧嬪�笺��
+ vo.setSigned(AuditConsts.TYPE_E_SIGNATURE.equals(e.getEventType()));
+ applySubTitles(vo, e.getExtra());
+ return vo;
+ }
+
+ /**
+ * 浠� extra.recordSubTitles 鍙栧瓙琛ㄦ爣棰樿锛屽彧涓嬪彂鍓� {@link #LIST_SUB_TITLE_LIMIT} 鏉� + 鎬绘暟銆�
+ * 涓嶆暣浣撲笅鍙� extra锛氭鏂囬噷闄� dataSnapshot 澶栬繕鏈夊悇绉嶆潵婧愭爣璁颁笌涓婁笅鏂囷紝鍒楄〃鎺ュ彛涓嶈甯﹀嚭鍘汇��
+ */
+ @SuppressWarnings("unchecked")
+ private void applySubTitles(AuditEventListVO vo, String extraJson) {
+ if (!StringUtils.hasText(extraJson)) {
+ return;
+ }
+ try {
+ Map<String, Object> extra = JsonUtil.stringToMap(extraJson);
+ Object raw = extra == null ? null : extra.get("recordSubTitles");
+ if (!(raw instanceof List)) {
+ return;
+ }
+ List<?> all = (List<?>) raw;
+ List<String> head = new ArrayList<>();
+ for (Object item : all) {
+ if (head.size() >= LIST_SUB_TITLE_LIMIT) {
+ break;
+ }
+ if (item != null) {
+ head.add(String.valueOf(item));
+ }
+ }
+ vo.setSubTitles(head);
+ vo.setSubTitleCount(all.size());
+ } catch (Throwable ignored) {
+ // extra 瑙f瀽澶辫触涓嶅奖鍝嶅垪琛ㄤ富琛屸�斺�旀爣棰樻槸閿︿笂娣昏姳锛屼笉鑳界偢鎺夋暣椤�
+ }
+ }
+
+ private AuditEventDetailVO toDetailVo(AuditEventEntity e) {
+ AuditEventDetailVO vo = new AuditEventDetailVO();
+ vo.setId(e.getId());
+ vo.setClientEventId(e.getClientEventId());
+ vo.setOperationId(e.getOperationId());
+ vo.setEventTime(e.getEventTime());
+ vo.setTenantId(e.getTenantId());
+ vo.setOperatorId(e.getOperatorId());
+ vo.setOperatorName(e.getOperatorName());
+ vo.setOperatorOrgId(e.getOperatorOrgId());
+ vo.setAppName(e.getAppName());
+ vo.setBizModule(e.getBizModule());
+ vo.setIp(e.getIp());
+ vo.setIpRegion(e.getIpRegion());
+ vo.setBrowser(e.getBrowser());
+ vo.setOs(e.getOs());
+ vo.setRequestUri(e.getRequestUri());
+ vo.setEventType(e.getEventType());
+ vo.setActionCode(e.getActionCode());
+ vo.setActionLabel(e.getActionLabel());
+ vo.setSourceLayer(e.getSourceLayer());
+ vo.setTargetTable(e.getTargetTable());
+ vo.setTargetId(AuditQueryResponseSanitizer.hidesTargetId(e.getTargetTable())
+ ? null : e.getTargetId());
+ vo.setBizType(e.getBizType());
+ vo.setBizCode(e.getBizCode());
+ String modelId = AuditQueryResponseSanitizer.sourceModelId(e.getExtra());
+ Map<String, jnpf.audit.diff.AuditFieldDiff.FieldMeta> metadata =
+ auditFormRegistry.resolveFieldMetadata(modelId, e.getTargetTable());
+ String sanitizedFieldDiffs = AuditQueryResponseSanitizer.sanitizeFieldDiffs(
+ e.getFieldDiffs(), metadata);
+ vo.setFieldDiffs(sanitizedFieldDiffs);
+ vo.setFieldDiffList(auditFieldDiffViewService.build(e, sanitizedFieldDiffs, metadata));
+ vo.setExtra(AuditQueryResponseSanitizer.sanitizeJson(e.getExtra()));
+ vo.setDataSnapshot(AuditQueryResponseSanitizer.sanitizeJson(e.getDataSnapshot(), metadata));
+ vo.setReason(e.getReason());
+ vo.setRecordTitle(e.getRecordTitle());
+ vo.setEntryType(e.getEntryType());
+ vo.setEntryId(e.getEntryId());
+ vo.setEntryName(e.getEntryName());
+ vo.setPrevHash(e.getPrevHash());
+ vo.setCreatedAt(e.getCreatedAt());
+ return vo;
+ }
+
+ /** field_diffs 鏄� VisualLogModel[] JSON锛涚┖/闈炴硶 JSON 涓�寰嬮檷绾т负 0锛屼笉璁╂憳瑕佽绠楃偢鍒楄〃鎺ュ彛銆� */
+ private Integer computeDiffCount(String fieldDiffs) {
+ if (!StringUtils.hasText(fieldDiffs)) {
+ return 0;
+ }
+ return AuditQueryResponseSanitizer.effectiveDiffCount(fieldDiffs);
+ }
+}
--
Gitblit v1.8.0