
구성
- 이벤트가 발생과 동시에 사용자 브라우저 오른쪽 아래 모달 창을 통해 확인 가능해야 함
- 기능 이름과 동작 문구를 통해 알림을 구별하도록 구성해야 함
- 시간 출력을 통해 실시간 임을 확인
- 5초 뒤에 자동으로 사라지도록 구성하고 여러 개가 올 경우, 화면에 쌓이는 모션을 추가
알림 구현 디비

- 그룹웨어의 다양한 기능들이 사용해야 하므로 기능 별 타입 값을 지정
- 알림을 받는 사람은 알림이 노출되어야 하는 사람의 pk 값
- 사원 번호는 이 알림을 보낸 사람의 pk 값
- 알림 노출 시간을 위한 알림 실시간 디비 시간
- 알림을 읽음 처리하고 개수를 차감하기 위한 알림 읽음 상태 값 구성
- 큰 구성은 이와 같지만 pk값이지만 실제 외래키는 많이 사용하지 않았음
- 기능 별로 사용되는 요청하는 사용자 번호가 다를 수 있어 입력하는 쪽으로 구성(전자 결재)
기능 별 사용 방법
//기능 별 js
alarmSocket.send(JSON.stringify({
type: 'nofication+본인 기능명',
데이터이름 : 데이터
}));
// 값을 실시간으로 보내고 싶을때 사용
// 버튼 동작과 함께 동작되게 해주세요.
// ex) 메시지를 전송할때 함수 안에 추가로 집어넣어 실시간으로 알림소켓과 연결
//자신의 기능 페이지이 동작하는 js에 디비에 저장해뒀던 타입을 선언하기
document.addEventListener("DOMContentLoaded", function() {
//필수로 넣기
window.functionType = 1; // 숫자는 꼭 디비의 본인 기능 숫자와 동일하게 해주세요.
console.log("현재 기능 타입: " +window.functionType);
if (window.functionType === 1) {
markNotificationsAsRead(window.functionType);
}
});
//알림 모달(공통 js)
const alarmModal = document.getElementById("notification-modal");
const closeButton = document.querySelector(".close-notification-modal");
function showNotification(title, content, memberNo, time, type, pk) {
if (memberNo === currentMember) {
const notificationContainer = document.getElementById("notificationContainer");
const notificationModal = document.createElement("div");
notificationModal.classList.add("notification-modal");
notificationModal.innerHTML = `
<div class="notification-modal-content" data-notification-type="${type}" data-notification-type-pk="${pk}">
<strong>${title}</strong>
<p>${content}</p>
<input type="hidden" name="memberNo" value="${memberNo}">
<span class="notification-time">${time}</span>
<span class="close-notification-modal">×</span>
</div>
`;
notificationContainer.appendChild(notificationModal);
setTimeout(() => {
notificationModal.classList.remove("show");
setTimeout(() => {
notificationModal.remove();
}, 400);
}, 7000);
notificationModal.querySelector('.close-notification-modal').addEventListener('click', function() {
notificationModal.classList.remove("show");
setTimeout(() => {
notificationModal.remove();
}, 400);
});
notificationModal.querySelector('.notification-modal-content').addEventListener('click', function() {
const notificationType = this.getAttribute('data-notification-type');
const notificationNo = this.getAttribute('data-notification-no');
const notificationTypePk = this.getAttribute('data-notification-type-pk');
if (noficationTypeUrl[notificationType]) {
if (notificationTypePk === null || notificationTypePk === '') {
window.location.href = noficationTypeUrl[notificationType];
} else {
window.location.href = noficationTypeUrl[notificationType] + notificationTypePk;
}
} else {
console.log('알 수 없는 알림 타입:', notificationType);
}
});
}
}
- 위처럼 예시 코드를 통해 다른 팀원들이 자신의 기능 타입을 통해 알림 웹소켓에 값이 도달할 수 있도록 구성
- 도달 후, 테이블에 해당 값들을 입력하고 성공하여 다시 js에 값을 보냄
- 그 값을 통해 메세지를 받아야 하는 사용자의 번호와 현재 로그인하고 있는 사용자의 번호가 동일하면 모달창이 노출될 수 있도록 함
트러블 슈팅
- 단순하게 페이지 진입하면 해당 알림을 볼 수 있고, 기능별 알림은 하나로 생각했으나, 전자 결재에서 문제 발생
- 전자 결재는 결재 순서에 따라 다음 사용자에게 알림이 가야하고, 알림을 읽지 않고 기능쪽 변화가 이루어지지 않는다면 그 다음 사람에게 알림이 가지 않아야 함
- 이를 고려하지 않고, 큰 기능 타입 번호를 구성하여 전자 결재 읽음 처리에도 문제 발생
해결
- 전자 결재를 위한 전자결재 pk값을 디비에 넣어 구성하기로 결정
- 디비에 너무 많은 값들이 들어가고 복잡한 만큼 조인을 줄이기 위해 정규화를 하지 않음
- 전자 결재를 제외한 다른 기능들은 해당 pk값이 기본 null로 구성되어 이를 통해 조건을 나누기로 결정
// 전자 결재(휴가 결재)
if (references != null && !references.isEmpty()) {
Long firstReference = references.get(0);
noficationDto.setNofication_content(nofication_content);
noficationDto.setNofication_receive_no(firstReference);
noficationDto.setNofication_title(nofication_title);
noficationDto.setNofication_type(nofication_type);
noficationDto.setMember_no(senderNo);
noficationDto.setNofication_type_pk(vacationApprovalPk);//휴가 결재 pk 전달
if (noficationService.insertAlarm(noficationDto) > 0) {
long notificationPk = noficationService.insertAlarmPk(); // pk값 추가
Map<String, Object> memberUnreadCount = new HashMap<>();
memberUnreadCount.put("memberNo", firstReference);
memberUnreadCount.put("nofication_pk", notificationPk);//같이 넘길 값
unreadCounts.add(memberUnreadCount);
}
}