div 팝업창을 만들어 보자.
이전글에서 임시 팝업창 작성을 해보았다. 이제 DB에 있는 데이터를 통해 실제 화면에 팝업창을 표출해보자.
현재 SM_POPUP 테이블에 적재되어 있는 데이터는 위와 같다.
내가 생각한 로직은 아래와 같다.
위 그림만 보면 이해 되겠지만,
현재날짜가 시작일과 종료일 사이에 있으면서 팝업이 공개인 데이터들만
SELECT해오고, 그중에 쿠키가 설정되어 있는 데이터만 추려서 화면에 표출한다.
( 위에서 SELECT 해오는 조건은 상황에 따라 바뀐다. 근데 가장 기본적인 건 위처럼 함.. )
그럼 조건에 맞는 데이터를 가져오는 로직을 우선 짜보자.
DB에서 조건에 맞는 팝업데이터 가져오기
HomeController.java
@RequestMapping(value = "/", method = RequestMethod.GET)
public String home(Locale locale, Model model) {
// map 생성자 생성
HashMap<String, Object> map = new HashMap<String, Object>();
// pop 데이터를 List타입으로 받아 popList에 넣어줌
List<PopInfoVO> popList = homeService.getPopupList();
// popList를 map에 put해줌.
map.put("popList", popList);
// 메인화면으로 이동
return "home";
}
HomeService.java
// Mapper 호출
public PopInfoVO getPopupList() {
return homeMapper.getPopupList();
}
HomeMapper.java
// 쿼리문 호출
public PopInfoVO getPopupList() {
return (PopInfoVO) session.selectList("pop.test.getPopupList");
}
testMapper.xml
<!-- PPUP_YN이 'Y'이면서 오늘날짜가 시작일과 종료일 사이에 있는 데이터만 SELECT -->
<select id="getPopupList" resultType="app.model.com.PopInfoVO">
SELECT
NTT_ID AS nttId,
PPUP_YN AS ppupYn,
POP_SUB AS popSub,
POP_CON AS popCon,
BEG_DE AS begDe,
END_DE AS endDe
FROM MOCHI.SM_POPUP
WHERE PPUP_YN = 'Y'
AND BEG_DE <![CDATA[<=]]> (SELECT to_char(CURRENT_DATE,'YYYY-MM-DD') FROM dual)
AND END_DE >= (SELECT to_char(CURRENT_DATE,'YYYY-MM-DD') FROM dual)
</select>
팝업창을 화면에 표출하기
home.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<!-- 필요한 라이브러리를 cdn에서 가져오기 시작 -->
<script src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js"></script>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.2.1.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/js/bootstrap-datepicker.min.js" integrity="sha512-T/tUfKSV1bihCnd+MxKD0Hm1uBBroVYBOYSk1knyvQ9VyZJpc/ALb4P0r6ubwVPSGB2GvjeoMAJJImBG12TiaQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/css/bootstrap-datepicker.min.css" integrity="sha512-mSYUmp1HYZDFaVKK//63EcZq4iFWFjxSL+Z3T/aCt4IO9Cejm03q3NKKYN6pFQzY0SBOr8h+eCIAZHPXcpZaNw==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-datepicker/1.9.0/locales/bootstrap-datepicker.ko.min.js" integrity="sha512-L4qpL1ZotXZLLe8Oo0ZyHrj/SweV7CieswUODAAPN/tnqN3PA1P+4qPu5vIryNor6HQ5o22NujIcAZIfyVXwbQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
<!-- 필요한 라이브러리를 cdn에서 가져오기 종료 -->
</head>
<body>
<!-- 팝업창 등록 페이지 -->
<%@ include file="/WEB-INF/views/insertPop.jsp" %>
<!-- 실제 팝업창 -->
<%@ include file="/WEB-INF/views/popup.jsp" %>
<!-- 팝업창에 스타일을 주기위한 css -->
<link rel="stylesheet" href="/com/resources/css/popStyle.css" />
</body>
</html>
popup.jsp
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Insert title here</title>
</head>
<script>
document.addEventListener("DOMContentLoaded", function(){
// 팝업창의 개수를 변수 n에 담아줌
var n = ${popList.size()};
// 만약 팝업창이 1개 이상이 존재한다면 아래 로직을 수행함
if(n!=0){
// 팝업창 개수에 따라 동적으로 스타일이 변하기 때문에 javascript로 스타일 처리함.
var top = 250;
var left = 0;
for(var i=0; i<n; i++){
// 현재 DOM에 존재하는 각 팝업창의 id값을 가져와 변수 element에 담아줌
var element = "#" + document.querySelector('.pop'+i).getAttribute('id');
/*
팝업창마다 css를 동적으로 변경해줌. top은 45씩 증가, left는 30씩 증가하도록 함.
ex) 팝업창 1 : top : 250px, left : 0px;
팝업창 2 : top : 295px, left : 30px;
팝업창 3 : top : 340px, left : 60px;
*/
top = top + 45;
left = left + 30;
document.querySelector(element).style.position = 'fixed';
document.querySelector(element).style.top = top + 'px';
document.querySelector(element).style.left = left + 'px';
document.querySelector(element).style.display = 'block';
}
}
/*
쿠키를 설정하는 함수.
name : id또는 class값
value : 쿠키를 설정함
expiredays : 며칠동안 쿠키를 유지할 것인가를 정하는 파라메터
*/
function setCookie( name, value, expiredays ) {
var todayDate = new Date();
todayDate.setDate( todayDate.getDate() + expiredays );
document.cookie = name + "=" + escape( value ) + "; path=/; expires=" + todayDate.toGMTString() + ";"
}
/*
팝업창을 닫는 함수
팝업창의 고유id값을 가져와 해당 id값과 일치하는 팝업창의 display 스타일 속성을 none으로 변경한다.
그리고 [하루동안 보지않음]에 해당하는 checkYn값이 체크되어 있는 지 확인한 뒤 체크가 되어 있다면
setCookie함수에 해당 팝업창 값과 기타 파라메터를 넣어 호출한다.
*/
closePop = function(nttId){
document.querySelector('#pop_'+nttId).style.display = 'none';
var checkYn = document.querySelector('.checkbox_'+nttId).checked;
if(checkYn){
setCookie( "pop_" + nttId , "done" , 1 );
}
};
/*
쿠키가 설정된(하루동안 보이지 않기 체크한) 팝업창을 변수 cookiedata에 담음
"pop_1=done"과 같은 형태로 담김
*/
var cookiedata = document.cookie.split("; ");
// 쿠키가 설정된 팝업창들을 배열 pop에 담아줌..
var pop = [];
pop =cookiedata.filter(function(item){return item.indexOf("pop_") !=-1;})
// 배열 pop의 길이만큼 for문을 돌리고
for(var i=0;i<pop.length;i++){
// 쿠키가 설정된 각 팝업창의 id값을 변수 id에 담아줌
var id = pop[i].split("=",1)
//만약 팝업창 배열의 속성값이 null이 아니면 해당 id값을 가지는 <div>팝업의 스타일속성 visibility를 hidden으로 변경함
$("#"+id).css("visibility","hidden");
}
});
</script>
<body>
<!-- 팝업시작 -->
<!-- 팝업창을 담은 배열이 null이 아닌 경우 아래 로직을 수행함 -->
<c:if test="${popList!=null}">
<!-- 팝업창 배열의 개수만큼 for문을 돌린다.. for문 안에서 <div>팝업창을 생성한다 -->
<c:forEach items="${popList}" var="popVo" varStatus="status">
<!-- div팝업창 -->
<div id="pop_${popVo.nttId}" class="modal pop${status.index}" tabindex="-1" style="width: 400px;">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title"><c:out value="${popVo.popSub}"/></h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<p><c:out value="${popVo.popCon}"/></p>
</div>
<div class="modal-footer">
<div class="form-check" style="position : relative; right : 140px;">
<input class="form-check-input checkbox_${popVo.nttId}" type="checkbox" value="" id="flexCheckDefault">
<label class="form-check-label" for="flexCheckDefault">
오늘하루 보지않기
</label>
</div>
<button type="button" class="btn btn-secondary close_${popVo.nttId}" data-bs-dismiss="modal" onclick="closePop(${popVo.nttId})">닫기</button>
</div>
</div>
</div>
</div>
</c:forEach>
</c:if>
<!-- 팝업종료 -->
</body>
</html>
위의 코드가 잘 이해되지 않는다면, 주석처리 된 부분을 잘 읽어보도록 하자.
결과는 아래와 같이 나온다.
이렇게 팝업이 여러개 생길수록 위치가 조금씩 변경되는 것을 볼 수 있다. 5개를 만들든 10개를 만들든 계속
위치가 조금씩 변경되며 전부 보인다.
여기서 "오늘하루 보지않기"를 체크하고 [닫기]버튼을 누르면 해당 팝업은 하루동안 보이지 않게 된다.
신입이 시절 개발팀에 처음 투입되고 게시판을 만들면서 팝업창 이녀석 때문에
고생을 많이 해서 이렇게 정리 겸, 글을 썼다. 신입시절 썼던 코드를 가져다 조금 수정을 했는데
( 제이쿼리를 바닐라js로 변경한 수준.. )
당시에는 javascript에 대한 지식도 없었고, 쿠키를 설정하는거나, css를 주는것도 몰랐었기 때문에 정말 고생했다.
선택자도 몰랐었던 시절.. 시간이 된다면 폼방식 말고 Vue를 써서 팝업창을 컴포넌트화 해봐야겠다.
'연습장' 카테고리의 다른 글
[연습장] 개인 라이브러리를 실제로 추가하여 사용해보자~ ( .jar 파일 사용 ) (0) | 2022.06.20 |
---|---|
[연습장] 개인 라이브러리를 만들어보자~ ( .jar 파일 만들기 ) (0) | 2022.06.17 |
[연습장] div 팝업창을 만들어 보자. - (1) 팝업 데이터 INSERT 하기 (0) | 2022.05.01 |
[연습장] Youtube Data API를 통한 유튜브 동영상 리스트를 만들어 보자. (8) 댓글 기능 구현 - 댓글 테이블에서 SELECT 해오기 (0) | 2022.03.18 |
[연습장] Youtube Data API를 통한 유튜브 동영상 리스트를 만들어 보자. (7) 댓글 기능 구현 - 댓글 테이블에 INSERT하기 (0) | 2022.03.17 |