Q&A 댓글 관련 코드 리팩토링 및 역할 기반 알림 기능 개선
eapim-portal CI / build (push) Has been cancelled
eapim-portal Test / test (push) Has been cancelled

- InquiryComment 코드 구조 리팩토링 및 역할 분리
- portal-admin 알림 기능 추가 및 예외 처리 개선
- InquiryComment 관련 불필요 클래스/메서드 제거
This commit is contained in:
Rinjae
2026-06-15 18:49:14 +09:00
parent 3f664bcd5c
commit 171feee9ea
18 changed files with 110 additions and 30 deletions
@@ -6,8 +6,10 @@ import com.eactive.apim.portal.apps.community.qna.mapper.InquiryMapper;
import com.eactive.apim.portal.common.user.PortalAuthenticatedUser;
import com.eactive.apim.portal.common.util.SecurityUtil;
import com.eactive.apim.portal.common.util.StringMaskingUtil;
import com.eactive.apim.portal.djb.community.qna.comment.service.InquiryAdminNotifier;
import com.eactive.apim.portal.portaluser.entity.PortalUserEnums;
import com.eactive.apim.portal.qna.entity.Inquiry;
import com.eactive.apim.portal.template.entity.MessageCode;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -15,6 +17,8 @@ import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
@Service
@RequiredArgsConstructor
@@ -22,6 +26,7 @@ public class InquiryFacadeImpl implements InquiryFacade {
private final InquiryService inquiryService;
private final InquiryMapper inquiryMapper;
private final InquiryAdminNotifier inquiryAdminNotifier;
@Override
public Page<InquiryDTO> getInquiries(InquirySearch search, Pageable pageable, PortalAuthenticatedUser user) {
@@ -81,9 +86,16 @@ public class InquiryFacadeImpl implements InquiryFacade {
@Override
public void createInquiry(InquiryDTO inquiryDTO) throws IOException {
PortalAuthenticatedUser current = SecurityUtil.getPortalAuthenticatedUser();
Inquiry inquiry = inquiryMapper.toEntity(inquiryDTO);
inquiry.setInquirer(SecurityUtil.getPortalAuthenticatedUser());
inquiry.setInquirer(current);
inquiryService.createInquiry(inquiry);
Map<String, Object> params = new HashMap<>();
params.put("inquiryId", inquiry.getId());
params.put("inquirySubject", inquiry.getInquirySubject());
params.put("writerName", current.getUserName());
inquiryAdminNotifier.notifyPortalAdmins(MessageCode.INQUIRY_CREATED, params);
}
@Override
@@ -12,7 +12,7 @@ import java.util.Map;
@Component
public class InquiryCommentCreatedAdminEvent implements MessageEventHandler {
public static final MessageCode KEY = MessageCode.INQUIRY_COMMENT_CREATED_ADMIN;
public static final MessageCode KEY = MessageCode.INQUIRY_COMMENT_CREATED;
@Override
public MessageCode getKey() {
@@ -0,0 +1,22 @@
package com.eactive.apim.portal.djb.community.qna.comment.repository;
import com.eactive.apim.portal.user.entity.UserInfo;
import com.eactive.eai.data.jpa.BaseRepository;
import com.eactive.eai.rms.data.EMSDataSource;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import java.util.List;
@EMSDataSource
public interface UserInfoRepository extends BaseRepository<UserInfo, String> {
/**
* TSEAIRM02.roleidnfiname 컬럼은 콤마로 구분된 복수 역할을 저장한다.
* (예: {@code "admin,portal-admin"}). Oracle native query로 콤마 토큰 매치.
*/
@Query(value = "SELECT * FROM TSEAIRM02 t"
+ " WHERE ',' || t.ROLEIDNFINAME || ',' LIKE '%,' || :role || ',%'",
nativeQuery = true)
List<UserInfo> findByRoleContaining(@Param("role") String role);
}
@@ -0,0 +1,57 @@
package com.eactive.apim.portal.djb.community.qna.comment.service;
import com.eactive.apim.portal.djb.community.qna.comment.repository.UserInfoRepository;
import com.eactive.apim.portal.djb.community.qna.constant.DjbAdminRole;
import com.eactive.apim.portal.template.entity.MessageCode;
import com.eactive.apim.portal.template.service.MessageHandlerService;
import com.eactive.apim.portal.template.service.MessageRecipient;
import com.eactive.apim.portal.user.entity.UserInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
/**
* Q&A 등록/댓글 등록 시 portal-admin 역할(TSEAIRM02)을 가진 관리자 전원에게
* 알림 메시지를 발행한다. 발송 실패는 트랜잭션 롤백을 유발하지 않는다.
*/
@Slf4j
@Service
@RequiredArgsConstructor
public class InquiryAdminNotifier {
private final UserInfoRepository userInfoRepository;
private final MessageHandlerService messageHandlerService;
public void notifyPortalAdmins(MessageCode code, Map<String, Object> params) {
try {
List<UserInfo> admins = userInfoRepository.findByRoleContaining(DjbAdminRole.PORTAL_ADMIN);
if (admins == null || admins.isEmpty()) {
log.warn("portal-admin 역할 관리자가 없습니다 — 알림 미발송 code={}", code.name());
return;
}
for (UserInfo admin : admins) {
try {
MessageRecipient recipient = toRecipient(admin);
messageHandlerService.publishEvent(code, recipient, params);
} catch (Exception e) {
log.warn("portal-admin 개별 알림 발행 실패 — userid={}, code={}",
admin.getUserid(), code.name(), e);
}
}
} catch (Exception e) {
log.warn("portal-admin 알림 발행 실패 — code={}", code.name(), e);
}
}
private MessageRecipient toRecipient(UserInfo admin) {
MessageRecipient r = new MessageRecipient();
r.setUsername(admin.getUsername());
r.setUserId(admin.getEmad());
r.setPhone(admin.getCphnno());
r.setMessengerId(admin.getUserid());
return r;
}
}
@@ -13,8 +13,6 @@ import com.eactive.apim.portal.portaluser.repository.PortalUserRepository;
import com.eactive.apim.portal.qna.entity.Inquiry;
import com.eactive.apim.portal.qna.entity.InquiryComment;
import com.eactive.apim.portal.template.entity.MessageCode;
import com.eactive.apim.portal.template.service.MessageHandlerService;
import com.eactive.apim.portal.template.service.MessageRecipient;
import com.eactive.apim.portal.user.entity.UserInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -44,7 +42,7 @@ public class InquiryCommentFacadeImpl implements InquiryCommentFacade {
private final InquiryCommentService commentService;
private final InquiryCommentRepository commentRepository;
private final InquiryCommentPermissionChecker permissionChecker;
private final MessageHandlerService messageHandlerService;
private final InquiryAdminNotifier adminNotifier;
private final PortalUserRepository portalUserRepository;
private final UserInfoRepository userInfoRepository;
@@ -96,21 +94,12 @@ public class InquiryCommentFacadeImpl implements InquiryCommentFacade {
}
private void publishAdminNotification(Inquiry inquiry, InquiryComment comment, PortalAuthenticatedUser current) {
try {
Map<String, Object> params = new HashMap<>();
params.put("inquiryId", inquiry.getId());
params.put("inquirySubject", inquiry.getInquirySubject());
params.put("commentContent", comment.getCommentDetail());
params.put("writerName", current.getUserName());
messageHandlerService.publishEvent(
MessageCode.INQUIRY_COMMENT_CREATED_ADMIN,
MessageRecipient.of(current),
params
);
} catch (Exception e) {
log.warn("Q&A 댓글 등록 관리자 알림 발행 실패 — inquiryId={}, commentId={}",
inquiry.getId(), comment.getId(), e);
}
Map<String, Object> params = new HashMap<>();
params.put("inquiryId", inquiry.getId());
params.put("inquirySubject", inquiry.getInquirySubject());
params.put("commentContent", comment.getCommentDetail());
params.put("writerName", current.getUserName());
adminNotifier.notifyPortalAdmins(MessageCode.INQUIRY_COMMENT_CREATED, params);
}
private Map<String, String> resolveWriterNames(List<InquiryComment> comments) {
@@ -0,0 +1,10 @@
package com.eactive.apim.portal.djb.community.qna.constant;
public final class DjbAdminRole {
/** TSEAIRM02.roleidnfiname 컬럼에서 포털 관리자를 식별하는 값. */
public static final String PORTAL_ADMIN = "portal-admin";
private DjbAdminRole() {
}
}
@@ -1,9 +0,0 @@
package com.eactive.apim.portal.djb.community.qna.comment.repository;
import com.eactive.apim.portal.user.entity.UserInfo;
import com.eactive.eai.data.jpa.BaseRepository;
import com.eactive.eai.rms.data.EMSDataSource;
@EMSDataSource
public interface UserInfoRepository extends BaseRepository<UserInfo, String> {
}