CustomPostUpdateEventListener.java
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xforce.admin.model.entity.admin.Policy;
import com.xforce.admin.model.entity.admin.PolicyHistory;
import com.xforce.admin.model.entity.admin.Server;
import com.xforce.admin.model.entity.admin.ServerHistory;
import com.xforce.admin.model.entity.common.AdminUser;
import com.xforce.admin.model.entity.common.AdminUserHistory;
import com.xforce.admin.model.repository.AdminUserHistoryRepository;
import com.xforce.admin.model.repository.PolicyHistoryRepository;
import com.xforce.admin.model.repository.ServerHistoryRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.event.spi.PostUpdateEvent;
import org.hibernate.event.spi.PostUpdateEventListener;
import org.hibernate.persister.entity.EntityPersister;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
@Slf4j
@Component
@RequiredArgsConstructor
public class CustomPostUpdateEventListener implements PostUpdateEventListener {
private final AdminUserHistoryRepository auditUserHistoryRepository;
private final PolicyHistoryRepository policyHistoryRepository;
private final ServerHistoryRepository serverHistoryRepository;
private final ObjectMapper objectMapper;
@Override
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void onPostUpdate(PostUpdateEvent event) {
Object entity = event.getEntity();
try {
if (entity instanceof AdminUser user) {
handleAdminUser(event, user);
} else if (entity instanceof Policy policy) {
handleAdminPolicy(event, policy);
} else if (entity instanceof Server server) {
handleAdminServer(event, server);
}
} catch (Exception e) {
log.error("Failed to save History. error: {}", entity.getClass().getSimpleName(), e);
throw new RuntimeException("History 저장 중 오류 발생", e);
}
}
private void handleAdminUser(PostUpdateEvent event, AdminUser user) throws Exception {
Set<String> ignoredFields = Set.of("userUpdatedAt", "lastLoginAt", "userUpdatedBy", "passwordUpdatedAt");
String jsonChanges = getJsonChanges(event, ignoredFields);
if (jsonChanges == null) return;
String reason = user.getChangedReason() != null ? user.getChangedReason() : "Update detected!";
AdminUserHistory history = AdminUserHistory.builder()
.userId(user.getUserId())
.changedFields(jsonChanges)
.changedReason(reason)
.changedBy(user.getUserUpdatedBy())
.build();
auditUserHistoryRepository.save(history);
}
private void handleAdminPolicy(PostUpdateEvent event, Policy policy) throws Exception {
Set<String> ignoredFields = Set.of(
"createdAt", "updatedAt", "createdBy", "updatedBy",
"deployedAt", "deployedBy", "deployedVersion");
String jsonChanges = getJsonChanges(event, ignoredFields);
if (jsonChanges == null) return;
String reason = policy.getChangedReason() != null ? policy.getChangedReason() : "Update detected!";
PolicyHistory history = PolicyHistory.builder()
.policyId(policy.getPolicyId())
.changedFields(jsonChanges)
.changedReason(reason)
.changedBy(policy.getUpdatedBy())
.build();
policyHistoryRepository.save(history);
}
private void handleAdminServer(PostUpdateEvent event, Server server) throws Exception {
Set<String> ignoredFields = Set.of(
"createdAt", "updatedAt", "createdBy", "updatedBy");
String jsonChanges = getJsonChanges(event, ignoredFields);
if (jsonChanges == null) return;
String reason = server.getChangedReason() != null ? server.getChangedReason() : "Update detected!";
ServerHistory history = ServerHistory.builder()
.serverId(server.getServerId())
.changedFields(jsonChanges)
.changedReason(reason)
.changedBy(server.getUpdatedBy())
.build();
serverHistoryRepository.save(history);
}
private String getJsonChanges(PostUpdateEvent event, Set<String> ignoredFields) throws Exception{
Map<String, Object> changes = new HashMap<>();
String[] propertyNames = event.getPersister().getPropertyNames();
Object[] oldState = event.getOldState();
Object[] newState = event.getState();
int[] dirtyProperties = event.getDirtyProperties();
for (int index : dirtyProperties) {
String fieldName = propertyNames[index];
if (ignoredFields.contains(fieldName)) {
continue;
}
Object oldValue = oldState[index];
Object newValue = newState[index];
if (oldValue == null && newValue == null) {continue;}
if (oldValue != null && oldValue.equals(newValue)) {continue;}
Map<String, Object> fieldChange = new HashMap<>();
fieldChange.put("old", oldState[index]);
fieldChange.put("new", newState[index]);
changes.put(fieldName, fieldChange);
}
if (changes.isEmpty()) return null;
return objectMapper.writeValueAsString(changes);
}
@Override
public boolean requiresPostCommitHandling(EntityPersister entityPersister) {
return false;
}
HibernateListener.java
@Component
@RequiredArgsConstructor
@Slf4j
public class HibernateListener {
private final EntityManagerFactory entityManagerFactory;
private final CustomPostUpdateEventListener customPostUpdateEventListener;
@PostConstruct
public void init() {
log.info("Initializing HibernateListener");
SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
EventListenerRegistry registry = sessionFactory.getServiceRegistry().getService(EventListenerRegistry.class);
registry.getEventListenerGroup(EventType.POST_UPDATE).appendListener(customPostUpdateEventListener);
}
}