Files
geg-gas-pcitc/itc-pcitc-dependencies/itc-pcitc-dependencies-service/src/main/java/com/pictc/utils/DataLogTools.java

1203 lines
40 KiB
Java
Raw Normal View History

2025-10-10 09:20:48 +08:00
package com.pictc.utils;
2025-12-18 09:57:16 +08:00
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.IdUtil;
2025-12-08 15:45:58 +08:00
import com.alibaba.fastjson.JSON;
import com.alibaba.nacos.shaded.com.google.common.collect.Lists;
2025-10-10 09:20:48 +08:00
import com.alibaba.nacos.shaded.com.google.common.collect.Maps;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.extension.conditions.query.QueryChainWrapper;
2025-12-18 09:57:16 +08:00
import com.pictc.annotations.datalog.*;
2025-10-10 09:20:48 +08:00
import com.pictc.converts.ConverUtil;
2025-12-18 09:57:16 +08:00
import com.pictc.datalog.*;
2025-10-21 17:28:41 +08:00
import com.pictc.enums.BusinessCode;
import com.pictc.enums.ExceptionCommonCode;
2025-10-10 09:20:48 +08:00
import com.pictc.exceptions.OrmException;
import com.pictc.jdbc.JdbcContext;
import com.pictc.jdbc.ResultSetUtils;
import com.pictc.jdbc.model.JdbcParam;
2025-10-21 17:28:41 +08:00
import com.xjrsoft.common.exception.BusinessException;
2025-10-10 09:20:48 +08:00
import com.xjrsoft.common.utils.SecureUtil;
import com.xjrsoft.module.datalog.entity.DataChangeLog;
import com.xjrsoft.module.datalog.entity.json.FieldChange;
import com.xjrsoft.module.datalog.mapper.DatalogMapper;
2025-10-22 10:42:00 +08:00
import com.xjrsoft.module.datalog.vo.DataChangeLogVo;
2025-10-10 09:20:48 +08:00
import com.xjrsoft.module.datalog.vo.OperationType;
import com.xjrsoft.module.organization.dto.UserDto;
import com.xjrsoft.module.system.client.IFileClient;
import com.xjrsoft.module.system.dto.LngFileUploadBindDto;
import com.xjrsoft.module.system.dto.UpdateLngFileUploadDto;
2025-10-10 09:20:48 +08:00
import lombok.NonNull;
import lombok.extern.slf4j.Slf4j;
2025-12-18 09:57:16 +08:00
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import javax.servlet.http.HttpServletRequest;
import javax.validation.Valid;
import java.io.Serializable;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.nio.charset.Charset;
import java.sql.Date;
import java.sql.*;
import java.time.*;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
2025-10-10 09:20:48 +08:00
@Slf4j
@SuppressWarnings({"unused","rawtypes","unchecked"})
@Component
public class DataLogTools {
private static Map<Class<?>,LogTableInfo> annotations = Maps.newHashMap();
2025-10-20 17:00:33 +08:00
private static Map<String,Class<?>> entitys = Maps.newHashMap();
2025-10-10 09:20:48 +08:00
private static Set<String> logTables = null;
private static Object lock = new Object();
2025-10-23 17:50:32 +08:00
public static final Set<String> excludeFields = SetUtils.of("id","tenantId","dataVersion","createUserId","createDate","modifyUserId","modifyDate","modifyDate","deleteMark");
2025-10-10 09:20:48 +08:00
2025-12-08 15:45:58 +08:00
public static final String SQL_LIST = "SELECT * FROM ${TBL_NAME} WHERE entity_id = ? ORDER BY operation_time DESC, flow_id DESC";
public static final String SQL_PLACEHOLDER = "\\$\\{TBL_NAME\\}";
private static DatalogMapper logDbService;
2025-10-10 09:20:48 +08:00
private static IFileClient fileClient;
@Autowired
public void setLogDbService(DatalogMapper logDbService) {
DataLogTools.logDbService = logDbService;
}
@Autowired
public void setFileClient(IFileClient fileClient) {
DataLogTools.fileClient = fileClient;
}
2025-10-10 09:20:48 +08:00
public static DataChangeLog createLog(Class<?> klazz,OperationType type) {
DataChangeLog createLog = createLog(klazz, type, null);
return createLog.setFlowId(IdUtil.getSnowflakeNextIdStr());
}
public static DataChangeLog createLog(Class<?> klazz,OperationType type,DataChangeLog parent) {
UserDto currentUser = SecureUtil.getCurrentUser();
LogTableInfo annotation = getAnnotation(klazz);
//变更人的IP地址
HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
String ipAddress = request.getRemoteAddr();
DataChangeLog changeLog = new DataChangeLog()
.setEntityClassName(klazz.getCanonicalName())
.setBusName(annotation.getName())
.setId(IdUtil.getSnowflakeNextIdStr())
.setOperationIp(ipAddress)
.setOperationType(type)
.setOperatorId(currentUser.getId())
.setOperatorName(currentUser.getName())
.setOperationTime(LocalDateTime.now());
if(parent!=null) {
changeLog.setFlowId(parent.getFlowId());
changeLog.setPid(parent.getId());
}
return changeLog;
}
public static LogTableInfo getAnnotation(Class<?> klazz) {
synchronized (lock) {
if(annotations.containsKey(klazz)) {
return annotations.get(klazz);
}
LogTableInfo tableInfo = new LogTableInfo(klazz);
if(tableInfo.isValid()) {
annotations.put(klazz,tableInfo);
return tableInfo;
}
return null;
}
}
public static <T>T insert(T entity) {
return insert(entity, new DefaultDataOperationListener<T>());
}
public static <T>T insert(T entity,DataOperationListener<T> listener) {
2025-10-10 09:20:48 +08:00
Class<? extends Object> klazz = entity.getClass();
List<DataChangeLog> logs = CollectionUtils.newArrayList();
DataChangeLog datalog = createLog(klazz,OperationType.INSERT);
LogTableInfo tabInfo = getAnnotation(klazz);
initJoinValue(entity,tabInfo,null);
Long idValue = tabInfo.getIdValue(entity);
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
DataOperationContent<T> content = null;
if(listener!=null) {
content = DataOperationContent.of(tabInfo,OperationType.INSERT,entity,null);
listener.before(content);
}
try {
mapper.insert(BeanUtil.toBean(entity,tabInfo.getEntityType()));
saveAttrs(tabInfo,entity);
datalog.setEntityId(idValue);
buildFields(datalog,tabInfo,entity,null);
logs.add(datalog);
List<LogJoinInfo> joins = tabInfo.getJoins();
if(CollectionUtils.isNotEmpty(joins)) {
for (LogJoinInfo join : joins) {
if(join.getJoin().caseType()==JoinCaseType.FULL) {
buildJoins(logs,datalog,OperationType.INSERT,tabInfo,join,entity);
}
2025-10-10 09:20:48 +08:00
}
}
if(listener!=null) {
listener.after(content);
}
saveLogs(tabInfo,logs);
} catch (Exception e) {
if(listener!=null) {
content.setError(e);
listener.onError(content);
}
throw e;
}finally {
if(listener!=null) {
listener.onFinally(content);
}
2025-10-10 09:20:48 +08:00
}
return entity;
}
private static <T> void saveAttrs(LogTableInfo tabInfo, T entity) {
saveAttrs(tabInfo, entity, false);
}
private static <T> void saveAttrs(LogTableInfo tabInfo, T entity,boolean remove) {
List<LogAttrFieldInfo> attrs = tabInfo.getAttrs();
if(CollectionUtils.isNotEmpty(attrs)) {
for (LogAttrFieldInfo item : attrs) {
LngFileUploadBindDto bindDto = new LngFileUploadBindDto();
bindDto.setTableId(tabInfo.getIdValue(entity));
bindDto.setTableName(item.getTableName());
bindDto.setColumnName(item.getField().getName());
bindDto.setRemove(remove);
if(item.isList()) {
bindDto.setFiles(tabInfo.getFieldValue(entity,item.getField()));
}else {
UpdateLngFileUploadDto vo = tabInfo.getFieldValue(entity,item.getField());
if(vo!=null) {
bindDto.setFiles(Lists.newArrayList(vo));
}
}
fileClient.bindTableData(bindDto);
}
}
}
2025-10-10 09:20:48 +08:00
public static <T>T update(T dto) {
return update(dto, new DefaultDataOperationListener<T>());
}
public static <T>T update(T dto,DataOperationListener<T> listener) {
2025-10-10 09:20:48 +08:00
Class<? extends Object> klazz = dto.getClass();
LogTableInfo tabInfo = getAnnotation(klazz);
Long idValue = tabInfo.getIdValue(dto);
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
T old = findById(klazz, idValue);
DataOperationContent<T> content = null;
if(listener!=null) {
content = DataOperationContent.of(tabInfo,OperationType.UPDATE,dto,old);
listener.before(content);
}
try {
if(old!=null) {
List<DataChangeLog> logs = CollectionUtils.newArrayList();
DataChangeLog datalog = createLog(klazz,OperationType.UPDATE);
initJoinValue(dto,tabInfo,null);
mapper.updateById(tabInfo.toEntity(dto));
saveAttrs(tabInfo,dto);
datalog.setEntityId(idValue);
buildFields(datalog,tabInfo,dto,old);
logs.add(datalog);
List<LogJoinInfo> joins = tabInfo.getJoins();
2025-12-18 09:57:16 +08:00
if(CollectionUtils.isNotEmpty(joins)) {
for (LogJoinInfo join : joins) {
if(join.getJoin().caseType()==JoinCaseType.FULL) {
buildJoins(logs,datalog,OperationType.UPDATE,tabInfo,join,dto);
}
2025-10-10 09:20:48 +08:00
}
}
if(listener!=null) {
listener.after(content);
}
saveLogs(tabInfo,logs);
}else {
throw new OrmException("数据不存在");
}
} catch (Exception e) {
if(listener!=null) {
content.setError(e);
listener.onError(content);
}
throw e;
} finally {
if(listener!=null) {
listener.onFinally(content);
2025-10-10 09:20:48 +08:00
}
}
return dto;
}
public static <T>T delete(T dto) {
return delete(dto, new DefaultDataOperationListener<T>());
}
2025-10-10 09:20:48 +08:00
public static <T>T delete(T entity,DataOperationListener<T> listener) {
2025-10-10 09:20:48 +08:00
Class<? extends Object> klazz = entity.getClass();
List<DataChangeLog> logs = CollectionUtils.newArrayList();
LogTableInfo tabInfo = getAnnotation(klazz);
Long idValue = tabInfo.getIdValue(entity);
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
T old = findById(klazz, idValue);
DataOperationContent<T> content = null;
if(listener!=null) {
content = DataOperationContent.of(tabInfo,OperationType.DELETE,old,null);
listener.before(content);
}
try {
DataChangeLog datalog = createLog(klazz,OperationType.DELETE);
datalog.setEntityId(idValue);
buildFields(datalog,tabInfo,entity,null);
logs.add(datalog);
delete(entity, tabInfo, mapper);
List<LogJoinInfo> joins = tabInfo.getJoins();
2025-12-18 09:57:16 +08:00
if(CollectionUtils.isNotEmpty(joins)) {
for (LogJoinInfo join : joins) {
if(join.getJoin().caseType()==JoinCaseType.FULL) {
buildJoins(logs,datalog,OperationType.DELETE,tabInfo,join,entity);
}
2025-10-10 09:20:48 +08:00
}
}
if(listener!=null) {
listener.after(content);
}
saveLogs(tabInfo,logs);
} catch (Exception e) {
if(listener!=null) {
content.setError(e);
listener.onError(content);
}
throw e;
}finally {
if(listener!=null) {
listener.onFinally(content);
}
2025-10-10 09:20:48 +08:00
}
return entity;
}
public static <T>boolean deleteByIds(Class<T> klazz, @Valid List<Long> ids) {
return deleteByIds(klazz, ids, new DefaultDataOperationListener<T>());
}
public static <T>boolean deleteByIds(Class<T> klazz, @Valid List<Long> ids,DataOperationListener<T> listener) {
2025-10-21 17:28:41 +08:00
for (Long id : ids) {
deleteById(klazz, id,listener);
2025-10-21 17:28:41 +08:00
}
return true;
}
2025-10-10 09:20:48 +08:00
public static <T>T deleteById(Class<T> klazz,Long id) {
return deleteById(klazz,id,new DefaultDataOperationListener<T>());
}
public static <T>T deleteById(Class<T> klazz,Long id,DataOperationListener<T> listener) {
2025-10-10 09:20:48 +08:00
LogTableInfo tabInfo = getAnnotation(klazz);
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
T entity = findById(klazz, id);
if(entity==null) return null;
DataOperationContent<T> content = null;
if(listener!=null) {
content = DataOperationContent.of(tabInfo,OperationType.DELETE,entity,null);
listener.before(content);
}
2025-10-10 09:20:48 +08:00
List<DataChangeLog> logs = CollectionUtils.newArrayList();
try {
delete(entity, tabInfo, mapper);
saveAttrs(tabInfo,entity,true);
DataChangeLog datalog = createLog(klazz,OperationType.DELETE);
datalog.setEntityId(id);
buildFields(datalog,tabInfo,entity,null);
logs.add(datalog);
List<LogJoinInfo> joins = tabInfo.getJoins();
2025-12-18 09:57:16 +08:00
if(CollectionUtils.isNotEmpty(joins)) {
for (LogJoinInfo join : joins) {
if(join.getJoin().caseType()==JoinCaseType.FULL) {
buildJoins(logs,datalog,OperationType.DELETE,tabInfo,join,entity);
}
2025-10-10 09:20:48 +08:00
}
}
if(listener!=null) {
listener.after(content);
}
saveLogs(tabInfo,logs);
} catch (Exception e) {
if(listener!=null) {
content.setError(e);
listener.onError(content);
}
throw e;
}finally {
if(listener!=null) {
listener.onFinally(content);
}
2025-10-10 09:20:48 +08:00
}
return entity;
}
2025-10-21 17:28:41 +08:00
private static void delete(Object entity,LogTableInfo tableinfo,BaseMapper mapper){
Long idValue = tableinfo.getIdValue(entity);
if(idValue!=null && idValue > 0) {
mapper.deleteById(idValue);
}else {
throw new BusinessException(BusinessCode.ofArgs(ExceptionCommonCode.DATA_DEL_ID_IS_NULL,tableinfo.getTableName()));
}
}
public static <T>boolean enable(Class<T> klazz,@Valid List<Long> ids) {
return enable(klazz, ids, new DefaultDataOperationListener<T>());
}
public static <T>boolean enable(Class<T> klazz, @Valid List<Long> ids,DataOperationListener<T> listener) {
2025-10-10 09:20:48 +08:00
for (Long id : ids) {
enableById(klazz, id,listener);
2025-10-21 17:28:41 +08:00
}
return true;
}
public static <T>T enableById(Class<T> klazz,Long id) {
return enableById(klazz, id, new DefaultDataOperationListener<T>());
}
public static <T>T enableById(Class<T> klazz,Long id,DataOperationListener<T> listener) {
2025-10-21 17:28:41 +08:00
LogTableInfo tabInfo = getAnnotation(klazz);
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
T old = findById(klazz, id);
2025-11-03 14:09:24 +08:00
if(old==null || tabInfo.isEnable(old)) return null;
DataOperationContent<T> content = null;
if(listener!=null) {
content = DataOperationContent.of(tabInfo,OperationType.ENABLE,old,old);
listener.before(content);
}
T entity = null;
try {
List<DataChangeLog> logs = CollectionUtils.newArrayList();
entity = findById(klazz, id);
content.setObj(entity);
DataChangeLog datalog = createLog(klazz,OperationType.ENABLE);
datalog.setEntityId(id);
buildFields(datalog,tabInfo,entity,old);
logs.add(datalog);
if(listener!=null) {
listener.after(content);
}
saveLogs(tabInfo,logs);
} catch (Exception e) {
if(listener!=null) {
content.setError(e);
listener.onError(content);
}
throw e;
}finally {
if(listener!=null) {
listener.onFinally(content);
}
}
return entity;
2025-10-21 17:28:41 +08:00
}
public static <T>boolean disable(Class<T> klazz,@Valid List<Long> ids) {
return disable(klazz, ids, new DefaultDataOperationListener<T>());
}
public static <T>boolean disable(Class<T> klazz, @Valid List<Long> ids,DataOperationListener<T> listener) {
2025-10-21 17:28:41 +08:00
for (Long id : ids) {
disableById(klazz, id,listener);
2025-10-10 09:20:48 +08:00
}
return true;
}
public static <T>T disableById(Class<T> klazz,Long id,DataOperationListener<T> listener) {
2025-10-21 17:28:41 +08:00
LogTableInfo tabInfo = getAnnotation(klazz);
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
T old = findById(klazz, id);
2025-11-03 14:09:24 +08:00
if(old==null || tabInfo.isDisable(old)) return null;
DataOperationContent<T> content = null;
if(listener!=null) {
content = DataOperationContent.of(tabInfo,OperationType.DISABLE,old,old);
listener.before(content);
}
T entity = null;
try {
List<DataChangeLog> logs = CollectionUtils.newArrayList();
entity = findById(klazz, id);
content.setObj(entity);
DataChangeLog datalog = createLog(klazz,OperationType.DISABLE);
datalog.setEntityId(id);
buildFields(datalog,tabInfo,entity,old);
logs.add(datalog);
if(listener!=null) {
listener.after(content);
}
saveLogs(tabInfo,logs);
} catch (Exception e) {
if(listener!=null) {
content.setError(e);
listener.onError(content);
}
throw e;
}finally {
if(listener!=null) {
listener.onFinally(content);
}
}
return entity;
2025-10-21 17:28:41 +08:00
}
public static <T>T findById(Class<?> klazz,Serializable id){
2025-10-10 09:20:48 +08:00
return findById(klazz,id,false);
}
public static <T>T findById(Class<?> klazz,Serializable id,boolean full){
2025-10-10 09:20:48 +08:00
LogTableInfo tabInfo = getAnnotation(klazz);
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
Object old = mapper.selectById(id);
if(old==null) return null;
T dto = (T) tabInfo.toDto(old);
initJoinValues(tabInfo,dto,SetUtils.of(klazz), full);
return dto;
}
2025-10-21 17:28:41 +08:00
2025-10-10 09:20:48 +08:00
2025-10-21 17:28:41 +08:00
private static Object findNativeById(Class<?> klazz, Serializable id) {
LogTableInfo tabInfo = getAnnotation(klazz);
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
return mapper.selectById(id);
}
2025-10-10 09:20:48 +08:00
public static void initJoinValues(LogTableInfo tabInfo,Object entity,Set<Class<?>> classPath,boolean full){
List<LogJoinInfo> joins = tabInfo.getJoins();
BaseMapper mapper = MybatisTools.getMapper(tabInfo.getEntityType());
2025-12-18 09:57:16 +08:00
if(CollectionUtils.isNotEmpty(joins)) {
2025-10-10 09:20:48 +08:00
for (LogJoinInfo join : joins) {
LogTableInfo joinTable = join.getTableInfo();
if(full) {
if(join.isList()) {
List joinList = getJoinList(joinTable,join, mapper,tabInfo,entity);
if(CollectionUtils.isNotEmpty(joinList)) {
List listVal = new ArrayList();
for (Object item : joinList) {
Object voOjb = BeanUtil.toBean(item,joinTable.getKlazz());
if(!classPath.contains(joinTable.getKlazz())) {
Set<Class<?>> classes = SetUtils.ofCollection(classPath);
classes.add(joinTable.getKlazz());
initJoinValues(joinTable,voOjb,classes,full);
}
listVal.add(voOjb);
}
tabInfo.setFieldValue(entity,join.getField(),listVal);
}
}else {
Object objVal = getJoinObj(joinTable,join, mapper,tabInfo,entity);
Object voOjb = BeanUtil.toBean(objVal,joinTable.getKlazz());
if(!classPath.contains(joinTable.getKlazz())) {
Set<Class<?>> classes = SetUtils.ofCollection(classPath);
classes.add(joinTable.getKlazz());
initJoinValues(joinTable,voOjb,classes,full);
}
tabInfo.setFieldValue(entity,join.getField(),voOjb);
}
}else {
if(join.getJoin().caseType()==JoinCaseType.FULL) {
if(join.isList()) {
List joinList = getJoinList(joinTable,join, mapper,tabInfo,entity);
if(CollectionUtils.isNotEmpty(joinList)) {
List listVal = new ArrayList();
for (Object item : joinList) {
Object voOjb = BeanUtil.toBean(item,joinTable.getKlazz());
if(!classPath.contains(joinTable.getKlazz())) {
Set<Class<?>> classes = SetUtils.ofCollection(classPath);
classes.add(joinTable.getKlazz());
initJoinValues(joinTable,voOjb,classes,full);
}
listVal.add(voOjb);
}
tabInfo.setFieldValue(entity,join.getField(),listVal);
}
}else {
Object objVal = getJoinObj(joinTable,join, mapper,tabInfo,entity);
Object voOjb = BeanUtil.toBean(objVal,joinTable.getKlazz());
if(!classPath.contains(joinTable.getKlazz())) {
Set<Class<?>> classes = SetUtils.ofCollection(classPath);
classes.add(joinTable.getKlazz());
initJoinValues(joinTable,voOjb,classes,full);
}
tabInfo.setFieldValue(entity,join.getField(),voOjb);
}
}
}
classPath.add(joinTable.getKlazz());
}
}
}
2025-10-21 17:28:41 +08:00
2025-10-10 09:20:48 +08:00
private static <T>void initJoinValue(T entity,LogTableInfo tabInfo,Set<Class<?>> classes) {
if(classes==null) {
classes = CollectionUtils.newHashSet();
}
if(classes.contains(tabInfo.getEntityType())) return ;
List<LogJoinInfo> joins = tabInfo.getJoins();
Long idValue = tabInfo.getIdValue(entity);
if(idValue == null || idValue <=0) {
idValue = IdWorker.getId();
tabInfo.setIdValue(entity,idValue);
}
classes.add(tabInfo.getEntityType());
2025-12-08 15:45:58 +08:00
if(CollectionUtils.isNotEmpty(joins)) {
2025-10-10 09:20:48 +08:00
for (LogJoinInfo join : joins) {
LogJoinColumn[] columns = join.getJoin().columns();
LogTableInfo joinTable = join.getTableInfo();
if(classes.contains(joinTable.getEntityType())) {
continue;
}
Object joinValue = tabInfo.getFieldValue(entity, join.getField());
if(joinValue!=null && joinValue instanceof List) {
List listValue = (List) joinValue;
for (LogJoinColumn joinColumn : columns) {
if (joinColumn.valueType() == JoinValueType.FEILD
&& joinColumn.valueDirection() == ValueDirectionType.RIGHT) {
Object joinFieldValue = tabInfo.getFieldValue(entity, joinColumn.field());
for (Object item : listValue) {
Long idValue2 = joinTable.getIdValue(item);
if(idValue2==null || idValue2 <=0) {
2025-12-16 14:33:35 +08:00
joinTable.setIdValue(item, IdWorker.getId());
2025-10-10 09:20:48 +08:00
}
joinTable.setFieldValue(item, joinColumn.relatedField(), joinFieldValue);
Set<Class<?>> joinClasses = SetUtils.ofCollection(classes);
initJoinValue(item,joinTable,joinClasses);
}
}
}
}else {
Long idValue2 = joinTable.getIdValue(joinValue);
if(idValue2==null || idValue2 <=0) {
joinTable.setIdValue(joinValue,idValue2);
}
for (LogJoinColumn joinColumn : columns) {
if(joinColumn.valueType()==JoinValueType.FEILD && joinColumn.valueDirection()==ValueDirectionType.LEFT) {
Object joinFieldValue = joinTable.getFieldValue(joinValue, joinColumn.relatedField());
tabInfo.setFieldValue(entity, joinColumn.field(),joinFieldValue);
}else {
Object joinFieldValue = tabInfo.getFieldValue(entity, joinColumn.field());
joinTable.setFieldValue(joinValue, joinColumn.relatedField(), joinFieldValue);
}
}
Set<Class<?>> joinClasses = SetUtils.ofCollection(classes);
initJoinValue(joinValue,joinTable,joinClasses);
}
}
}
}
private static <T>void buildJoins(List<DataChangeLog> logs,DataChangeLog parent,OperationType type,LogTableInfo parentInfo, LogJoinInfo join, T entity) {
LogTableInfo joinTable = join.getTableInfo();
BaseMapper mapper = MybatisTools.getMapper(joinTable.getEntityType());
if(joinTable!=null) {
if(join.isList()) {
List listValue = BeanUtils.getFieldValue(join.getField(),entity);
if(CollectionUtils.isNotEmpty(listValue)) {
if(type==OperationType.INSERT || type==OperationType.DELETE) {
if(type==OperationType.INSERT) {
for (Object item : listValue) {
Long idValue = joinTable.getIdValue(item);
DataChangeLog datalog = createLog(join.getTargetClass(),type,parent);
datalog.setEntityId(idValue);
Object bean = BeanUtil.toBean(item,joinTable.getEntityType());
mapper.insert(bean);
saveAttrs(joinTable,item);
2025-10-10 09:20:48 +08:00
buildFields(datalog,joinTable,item,null);
logs.add(datalog);
}
}else {
for (Object item : listValue) {
Long idValue = joinTable.getIdValue(item);
DataChangeLog datalog = createLog(join.getTargetClass(),type,parent);
datalog.setEntityId(idValue);
Object pojo = BeanUtil.toBean(item,joinTable.getKlazz());
delete(pojo, joinTable, mapper);
saveAttrs(joinTable,item,true);
buildFields(datalog,joinTable,item,null);
2025-10-10 09:20:48 +08:00
logs.add(datalog);
}
}
}else {
for (Object item : listValue) {
Long idValue = joinTable.getIdValue(item);
DataChangeLog datalog = createLog(join.getTargetClass(),type,parent);
datalog.setEntityId(idValue);
Object old = findById(join.getTargetClass(), idValue);
Object pojo = BeanUtil.toBean(item,joinTable.getKlazz());
mapper.updateById(pojo);
saveAttrs(joinTable,item);
buildFields(datalog,joinTable,item,old);
2025-10-10 09:20:48 +08:00
logs.add(datalog);
}
}
} else if(type==OperationType.UPDATE || type==OperationType.DELETE){
//进行修改或者删除时,级联对象为空时,需要删除旧数据
List oldList = getJoinList(joinTable, join, mapper, parentInfo, entity);
if(oldList!=null) {
for (Object item : oldList) {
Long idValue = joinTable.getIdValue(item);
DataChangeLog datalog = createLog(join.getTargetClass(),OperationType.DELETE,parent);
datalog.setEntityId(idValue);
Object pojo = BeanUtil.toBean(item,joinTable.getKlazz());
delete(pojo, joinTable, mapper);
saveAttrs(joinTable,item,true);
buildFields(datalog,joinTable,item,null);
2025-10-10 09:20:48 +08:00
logs.add(datalog);
}
}
}
} else {
Object val = BeanUtils.getFieldValue(join.getField(),entity);
if(val!=null) {
Long idValue = joinTable.getIdValue(val);
DataChangeLog datalog = createLog(join.getTargetClass(),type,parent);
logs.add(datalog);
datalog.setEntityId(idValue);
Object pojo = BeanUtil.toBean(val,joinTable.getKlazz());
2025-10-10 09:20:48 +08:00
if(type==OperationType.INSERT || type==OperationType.DELETE) {
if(type==OperationType.INSERT) {
mapper.insert(pojo);
saveAttrs(joinTable,val);
2025-10-10 09:20:48 +08:00
}else {
delete(pojo, joinTable, mapper);
saveAttrs(joinTable,val,true);
2025-10-10 09:20:48 +08:00
}
buildFields(datalog,joinTable, val, null);
}else {
Object old = mapper.selectById(idValue);
mapper.updateById(pojo);
saveAttrs(joinTable,val,true);
2025-10-10 09:20:48 +08:00
buildFields(datalog,joinTable,val,old);
}
} else if(type==OperationType.UPDATE || type==OperationType.DELETE){
//进行修改或者删除时,级联对象为空时,需要删除旧数据
Object old = getJoinObj(joinTable, join, mapper, parentInfo, entity);
if(old!=null) {
Object dto = BeanUtil.toBean(old,joinTable.getKlazz());
2025-10-10 09:20:48 +08:00
Long idValue = joinTable.getIdValue(old);
DataChangeLog datalog = createLog(join.getTargetClass(),OperationType.DELETE,parent);
datalog.setEntityId(idValue);
delete(dto, joinTable, mapper);
saveAttrs(joinTable,dto,true);
buildFields(datalog,joinTable,dto,null);
2025-10-10 09:20:48 +08:00
}
}
}
}
}
private static List getJoinList(LogTableInfo joinTable, LogJoinInfo join, BaseMapper mapper,
LogTableInfo parentInfo,Object parent) {
LogJoin joinAnnotation = join.getJoin();
LogJoinColumn[] columns = joinAnnotation.columns();
QueryChainWrapper queryWrapper = new QueryChainWrapper(mapper);
for (LogJoinColumn joinCol : columns) {
if(joinCol.valueType()==JoinValueType.FEILD) {
Object value = parentInfo.getFieldValue(parent,joinCol.field());
if(value==null) return null;
queryWrapper.eq(joinTable.getColumn(joinCol.relatedField()),value);
}else {
if(StringUtils.isNotEmpty(joinCol.relatedField())) {
queryWrapper.eq(joinTable.getColumn(joinCol.relatedField()),ConverUtil.jsonToValue(joinCol.staticType(),joinCol.staticValue()));
}
}
}
return mapper.selectList(queryWrapper);
}
private static Object getJoinObj(LogTableInfo joinTable,LogJoinInfo join,BaseMapper mapper,LogTableInfo parentInfo,Object parent) {
LogJoin joinAnnotation = join.getJoin();
LogJoinColumn[] columns = joinAnnotation.columns();
QueryChainWrapper query = new QueryChainWrapper(mapper);
for (LogJoinColumn joinCol : columns) {
if(joinCol.valueType()==JoinValueType.FEILD) {
Object value = parentInfo.getFieldValue(parent,joinCol.field());
if(value==null) return null;
query.eq(joinTable.getColumn(joinCol.relatedField()),value);
}else {
if(StringUtils.isNotEmpty(joinCol.relatedField())) {
query.eq(joinTable.getColumn(joinCol.relatedField()),ConverUtil.jsonToValue(joinCol.staticType(),joinCol.staticValue()));
}
}
}
return mapper.selectObjs(query);
}
private static <T>void buildFields(DataChangeLog datalog,LogTableInfo tableInfo,T entity,T old) {
List<LogFieldInfo> fields = tableInfo.getFields();
for (LogFieldInfo item : fields) {
if(excludeFields.contains(item.getFieldName())) {
continue;
}
FieldChange change = new FieldChange();
change.setField(item.getFieldName());
change.setName(item.getName());
2025-10-24 08:29:58 +08:00
Object newVal = BeanUtils.getFieldValue(item.getField(),entity);
2025-10-10 09:20:48 +08:00
if(old!=null) {
Object oldVal = BeanUtils.getFieldValue(item.getField(),old);
boolean flag = false;
boolean isString = String.class.equals(item.getJavaType());
if(newVal==null && oldVal!=null) {
flag = isString?StringUtils.isNotEmpty((String)oldVal):true;
}else if(newVal!=null && oldVal==null) {
flag = isString?StringUtils.isNotEmpty((String)newVal):true;
2025-10-10 09:20:48 +08:00
}else if(newVal!=null && oldVal!=null && !newVal.equals(oldVal)) {
flag = true;
}
change.setOldValue(parseValue(oldVal,item.getJavaType()));
change.setNewValue(parseValue(newVal,item.getJavaType()));
if(flag) {
datalog.addFiledChnage(change);
}
}else {
change.setNewValue(parseValue(BeanUtils.getFieldValue(item.getField(),entity),item.getField().getType()));
datalog.addFiledChnage(change);
}
}
}
private static String parseValue(Object val,Class<?> type) {
if(val==null) return null;
if (type.equals(String.class)) {
return String.class.cast(val);
} else if (type.equals(BigDecimal.class)) {
return BigDecimal.class.cast(val).toString();
} else if (type.equals(BigInteger.class)) {
return BigInteger.class.cast(val).toString();
} else if (type.equals(Boolean.class) || type.equals(Boolean.TYPE)
|| type.equals(Integer.class) || type.equals(Integer.TYPE)
|| type.equals(Long.class) || type.equals(Long.TYPE)
|| type.equals(Float.class) || type.equals(Float.TYPE)
|| type.equals(Double.class) || type.equals(Double.TYPE)
) {
return val.toString();
} else if (type.equals(byte[].class)) {
byte[] buf = (byte[])val;
return new String(buf, Charset.forName("UTF-8"));
} else if (type.equals(Date.class) || type.equals(Time.class) || type.equals(Timestamp.class) || type.equals(java.util.Date.class)) {
String fmt = null;
if(type.equals(Date.class)) {
fmt = DateUtils.GENERAL;
}else if(type.equals(Time.class)) {
fmt = DateUtils.FMT_TIME;
}else {
fmt = DateUtils.LONG_FORMAT;
}
return DateUtils.format(java.util.Date.class.cast(val),fmt);
}else if (type.equals(LocalDate.class)) {
return DateUtils.format(LocalDate.class.cast(val));
} else if (type.equals(LocalDateTime.class)) {
return DateUtils.format(LocalDateTime.class.cast(val));
} else if (type.equals(LocalTime.class)) {
return DateUtils.format(LocalDateTime.class.cast(val));
} else if (type.equals(OffsetDateTime.class)) {
return DateUtils.format(OffsetDateTime.class.cast(val));
} else if (type.equals(OffsetTime.class)) {
return DateUtils.format(OffsetTime.class.cast(val));
}else if(type.isEnum()) {
return val.toString();
}
return null;
}
/**
* @Description: 判断是否有子表数据日志
* @param item
* @param pidMap
* @return boolean 返回类型
*/
private static boolean hasChild(DataChangeLog item,Map<String, List<DataChangeLog>> pidMap) {
if(!pidMap.containsKey(item.getId())) {
return false;
}
boolean flag = false;
List<DataChangeLog> childs = pidMap.get(item.getId());
for (DataChangeLog child : childs) {
if(child.hasFieldChanges() || hasChild(child,pidMap)) {
flag = true;
break;
}
}
return flag;
}
2025-10-10 09:20:48 +08:00
/**
* @Description: 保存数据日志
* @param logs 日志记录对象
* @return void 返回类型
*/
public static void saveLogs(LogTableInfo tableInfo,List<DataChangeLog> logs) {
String tableName = parseLogTableName(tableInfo);
initTable(tableName);
// String sql = parseSql(SQL_INSERT, tableName);
// List<List<JdbcParam>> batchParams = CollectionUtils.newArrayList();
// Map<String, List<DataChangeLog>> pidMap = logs.stream().collect(Collectors.groupingBy(DataChangeLog::getPid));
//
// for (DataChangeLog item : logs) {
// //没有改变的属性,且没有子表修改时跳过
// if(!item.hasFieldChanges() && !hasChild(item, pidMap)) {
// continue;
// }
//
// List<JdbcParam> params = CollectionUtils.newArrayList();
// params.add(JdbcParam.of(Types.VARCHAR,String.class, item.getId()));
// params.add(JdbcParam.of(Types.VARCHAR,String.class, item.getFlowId()));
// params.add(JdbcParam.of(Types.VARCHAR,String.class, item.getPid()));
// params.add(JdbcParam.of(Types.VARCHAR,String.class, item.getEntityClassName()));
// params.add(JdbcParam.of(Types.VARCHAR,String.class, item.getBusName()));
// params.add(JdbcParam.of(Types.BIGINT,long.class, item.getEntityId()));
// params.add(JdbcParam.of(Types.VARCHAR,String.class,JSON.toJSONString(item.getFieldChanges())));
// params.add(JdbcParam.of(Types.VARCHAR,String.class,item.getOperationType().name()));
// params.add(JdbcParam.of(Types.VARCHAR,long.class,item.getOperatorId()));
// params.add(JdbcParam.of(Types.VARCHAR,String.class,item.getOperatorName()));
// params.add(JdbcParam.of(Types.TIMESTAMP,Timestamp.class,item.getOperationTime()));
// params.add(JdbcParam.of(Types.VARCHAR,String.class,item.getOperationIp()));
// batchParams.add(params);
// }
// executeBatch(sql, batchParams);
for (DataChangeLog item : logs) {
2025-12-02 10:21:46 +08:00
if(item.hasFieldChanges()) {
2025-12-08 15:45:58 +08:00
logDbService.insertDataLog(tableName,item.getId(),
item.getFlowId(), // 2. flow_id
item.getPid(), // 3. pid
item.getEntityClassName(), // 4. entity_class_name
item.getBusName(), // 5. bus_name
item.getEntityId(), // 6. entity_id
JSON.toJSONString(item.getFieldChanges()), // 7. field_changes可传 JSON 字符串)
item.getOperationType().name(), // 8. operation_type如 "INSERT/UPDATE/DELETE"
item.getOperatorId(), // 9. operator_id
item.getOperatorName(), // 10. operator_name
item.getOperationTime(), // 11. operation_timeDate 类型MyBatis 自动转数据库时间类型)
item.getOperationIp());
2025-12-02 10:21:46 +08:00
}
2025-10-10 09:20:48 +08:00
}
}
/**
* @Description: 初始化日志表
* @param tableName
* @return void 返回类型
*/
private synchronized static boolean initTable(String tableName) {
synchronized (lock) {
//如果没有日志表时,重新创建
if(!hasTable(tableName)) {
logDbService.createDatalogTable(tableName);
logDbService.addTableInfo(tableName);
2025-10-10 09:20:48 +08:00
logTables.add(tableName);
log.info("新增数据日志表:{}",tableName);
return true;
}
}
return false;
}
private static boolean hasTable(String tableName) {
synchronized (lock) {
if(logTables==null) {
List<String> tabs = logDbService.getTableList();
2025-10-10 09:20:48 +08:00
logTables = new HashSet<String>(tabs);
}
if(logTables.contains(tableName)) return true;
Long count = logDbService.getCountByTableName(tableName);
2025-10-10 09:20:48 +08:00
boolean flag = count!=null && count > 0;
if(flag) {
logTables.add(tableName);
}
return flag;
}
}
2025-10-20 17:00:33 +08:00
/**
* @Description: TODO(这里用一句话描述这个方法的作用)
* @param clazz
* @param dataId
* @return List<DataChangeLog> 返回类型
*/
2025-10-22 10:42:00 +08:00
public static <T>List<DataChangeLogVo> findLogsByEntityId(Class<?> clazz,@NonNull Long dataId) {
2025-10-20 17:00:33 +08:00
LogTableInfo tabInfo = getAnnotation(clazz);
String tableName = parseLogTableName(tabInfo);
return findLogsByEntityId(tableName, dataId);
}
2025-10-10 09:20:48 +08:00
/**
* @Description: 根据数据id获取操作日志
2025-10-20 17:00:33 +08:00
* @param tableName 表名
2025-10-10 09:20:48 +08:00
* @param dataId 数据id
* @return List<DataChangeLog> 返回类型
*/
2025-10-22 10:42:00 +08:00
public static <T>List<DataChangeLogVo> findLogsByEntityId(String tableName,@NonNull Long dataId) {
2025-10-10 09:20:48 +08:00
if(initTable(tableName)) {
return null;
}
2025-12-08 15:45:58 +08:00
String sql = parseSql(SQL_LIST, tableName);
JdbcContext context = null;
try {
List<DataChangeLog> result = CollectionUtils.newArrayList();
context = new JdbcContext(true,true);
context.init(sql);
context.setParams(ListUtils.ofArray(JdbcParam.ofLong(dataId)));
ResultSet set = context.executeQuery();
Map<String, String> names = ResultSetUtils.getMapColumns(set);
while (set.next()) {
DataChangeLog log = new DataChangeLog();
log.setId(set.getString("id"));
log.setFlowId(set.getString("flow_id"));
log.setPid(set.getString("pid"));
log.setEntityClassName(set.getString("entity_class_name"));
log.setBusName(set.getString("bus_name"));
log.setEntityId(set.getLong("entity_id"));
log.setOperationType(OperationType.valueOf(set.getString("operation_type")));
log.setOperationIp(set.getString("operation_ip"));
log.setOperatorId(set.getLong("operator_id"));
log.setOperatorName(set.getString("operator_name"));
log.setOperationTime(ResultSetUtils.getObject(set,"operation_time",LocalDateTime.class));
String json = set.getString("field_changes");
if(StringUtils.isNotEmpty(json)) {
log.setFieldChanges(JSON.parseArray(json).toJavaList(FieldChange.class));
}
result.add(log);
}
return toVo(result);
} catch (SQLException e) {
throw context.createException(e);
} finally {
context.end();
}
2025-10-10 09:20:48 +08:00
}
2025-10-22 10:42:00 +08:00
private static List<DataChangeLogVo> toVo(List<DataChangeLog> list){
List<DataChangeLogVo> result = CollectionUtils.newArrayList();
if(CollectionUtils.isNotEmpty(list)) {
Map<String, List<DataChangeLog>> flowGroup = list.stream().collect(Collectors.groupingBy(DataChangeLog::getFlowId));
for (Entry<String, List<DataChangeLog>> entry : flowGroup.entrySet()) {
Map<String, List<DataChangeLog>> pidMap = entry.getValue().stream().collect(Collectors.groupingBy(DataChangeLog::getPid));
DataChangeLog root = pidMap.get("#").get(0);
2025-10-22 14:47:05 +08:00
DataChangeLogVo vo = toVo(root);
addChildVo(root,vo,pidMap);
2025-10-22 10:42:00 +08:00
result.add(vo);
}
}
2025-10-22 14:47:05 +08:00
Collections.sort(result,new Comparator<DataChangeLogVo>() {
@Override
public int compare(DataChangeLogVo o1, DataChangeLogVo o2) {
return Long.valueOf(o2.getSort()-o1.getSort()).intValue();
}
});
2025-10-22 10:42:00 +08:00
return result;
}
2025-10-22 14:47:05 +08:00
private static void addChildVo(DataChangeLog current,DataChangeLogVo parentVo,Map<String, List<DataChangeLog>> pidMap){
List<DataChangeLog> childs = pidMap.get(current.getId());
if(CollectionUtils.isNotEmpty(childs)) {
for (DataChangeLog item : childs) {
DataChangeLogVo logVo = toVo(item,parentVo.getId());
parentVo.addChild(logVo);
addChildVo(item, logVo, pidMap);
}
}
}
2025-10-22 10:42:00 +08:00
private static DataChangeLogVo toVo(DataChangeLog obj){
2025-10-22 14:47:05 +08:00
return toVo(obj, obj.getPid());
}
private static long toMills(LocalDateTime datetime) {
ZonedDateTime systemZoned = datetime.atZone(ZoneId.systemDefault());
return systemZoned.toInstant().toEpochMilli();
}
private static DataChangeLogVo toVo(DataChangeLog obj,String pid){
2025-10-22 10:42:00 +08:00
DataChangeLogVo vo = new DataChangeLogVo();
vo.setId(obj.getId());
2025-10-22 14:47:05 +08:00
vo.setPid(pid);
2025-10-22 10:42:00 +08:00
vo.setTableName(obj.getBusName());
vo.setOperationType(obj.getOperationType());
2025-10-22 10:47:12 +08:00
vo.setOperatorName(obj.getOperatorName());
vo.setOperationIp(obj.getOperationIp());
vo.setOperationTime(DateUtils.format(obj.getOperationTime()));
2025-10-22 14:47:05 +08:00
vo.setSort(toMills(obj.getOperationTime()));
2025-10-22 10:47:12 +08:00
List<FieldChange> fieldChanges = obj.getFieldChanges();
2025-10-22 14:47:05 +08:00
for (FieldChange fieldChange : fieldChanges) {
DataChangeLogVo fvo = new DataChangeLogVo();
fvo.setId(obj.getId()+"_"+fieldChange.getField());
fvo.setPid(obj.getId());
fvo.setName(fieldChange.getName());
2025-10-22 14:47:05 +08:00
fvo.setOldValue(fieldChange.getOldValue());
fvo.setNewValue(fieldChange.getNewValue());
fvo.setOperationType(obj.getOperationType());
fvo.setOperatorName(obj.getOperatorName());
fvo.setOperationIp(obj.getOperationIp());
fvo.setOperationTime(DateUtils.format(obj.getOperationTime()));
vo.addChild(fvo);
}
2025-10-22 10:42:00 +08:00
return vo;
}
2025-10-10 09:20:48 +08:00
private static String parseLogTableName(LogTableInfo tableInfo) {
String name = tableInfo.getTableName();
return "datalog_"+name;
}
/**
* 执行ddl语句
* */
public static boolean execute(String sql){
JdbcContext context = null;
try {
context = new JdbcContext(true,true);
context.init(sql);
return context.execute();
} catch (SQLException e) {
throw context.createException(e);
}finally {
context.end();
}
}
/**
* 修改操作
* */
public static int executeUpdate(String sql,List<JdbcParam> params){
JdbcContext context = null;
try {
context = new JdbcContext(true,true);
context.init(sql);
context.setParams(params);
return context.executeUpdate();
} catch (SQLException e) {
throw context.createException(e);
}finally {
context.end();
}
}
/**
* 批量操作
* */
public static int executeBatch(String sql,List<List<JdbcParam>> batchParams){
JdbcContext context = null;
try {
context = new JdbcContext(true,true);
context.init(sql);
context.setBatchParams(batchParams);
return context.executeBatch(-1);
} catch (SQLException e) {
throw context.createException(e);
}finally {
context.end();
}
}
/**
* 查询基础数据类型
* */
public static <T>T queryPrimitive(String sql,Class<T> type,List<JdbcParam> params){
JdbcContext context = null;
try {
context = new JdbcContext(true,true);
context.init(sql);
context.setParams(params);
ResultSet set = context.executeQuery();
while (set.next()) {
return ResultSetUtils.getObject(set,1,type);
}
} catch (SQLException e) {
throw context.createException(e);
}finally {
context.end();
}
return null;
}
/**
* 查询基础数据类型
* */
public static <T>List<T> queryListPrimitive(String sql,Class<T> type,List<JdbcParam> params){
JdbcContext context = null;
try {
context = new JdbcContext(true,true);
context.init(sql);
context.setParams(params);
ResultSet set = context.executeQuery();
List<T> res = CollectionUtils.newArrayList();
while (set.next()) {
res.add(ResultSetUtils.getObject(set,1,type));
}
return res;
} catch (SQLException e) {
throw context.createException(e);
}finally {
context.end();
}
}
2025-12-08 15:45:58 +08:00
private static String parseSql(String sql,String tableName) {
return sql.replaceAll(SQL_PLACEHOLDER,tableName);
}
2025-10-10 09:20:48 +08:00
2025-10-21 17:28:41 +08:00
2025-10-10 09:20:48 +08:00
}