본문 바로가기

📚Study Note/JSP Servlet

[ JSP ] 달력을 출력하는 JSP 페이지 │ select box 선택 시 │ 단독페이지

코드는 약간 길지만 아주 쉽..

차근차근 시작해봅시다

 

우선 결과는 이렇게 나온다. 선택된 날짜라고 되어있는 부분은 데이터가 어떻게 변경되는지 확인하려고 추가한 부분이다. 달력에 * 이 있는 부분도 어떤 부분이 공백인지 표현하기 위해서 넣었다. 
<body> 영역 안에 있는 코드이다. 저기서 onchange="submit ~~ 에서 submit 은 내가 임의로 정한 함수명일 뿐이다.  select box 의 option 태그들은 테스트용이므로 무시해도 된다, 

우선 submit 버튼이 없이 select box 를 선택하면 바로 데이터를 전송해서 달력을 그려야 하므로 

onchange = "함수명(this.form)" 을 통해 스크립트 함수에 form 객체를 매개변수로 넘겨서 그것을 submit() 해줄 것이다. 

 

 

 이렇게 스크립트 함수 submit(obj) 를 통해서 form 객체를 넘겨주게 된다. 

위에서 action 속성을 따로 주지 않았기 때문에 넘겨주게 되면 받게 되는 주체는 자기 자신이다. 

자신이 던지고 자신이 받는 격?

따라서 스크립트릿 영역에서 name 속성을 통해서 select box 에서 선택한 내용을 받을 수 있다.

 

<%%> 스크립트릿 영역 안의 코드이다.  

 

<%%> 스크립트릿 영역 안의 코드이다.  

우선 페이지가 로드됐을 때 보여지는 첫 번째 달력을 그리기 위해서는 현재의 날짜를 알아야 한다. 캘린더 객체를 생성해서 현재의 year, month, day를 받는다. (우선 여기서 day 는 쓰일 일이 당장 없어서 무시해도 된다. )

현재의 년도와 월만 알면 달력을 그릴 수 있기 때문이다. 

 

달력을 그릴 기준이 되는 년, 월을 담는 변수는 selectYear 과 selectMonth 라는 변수이다. 

이 값은 페이지가 로드 되자마자 현재의 날짜로 설정이 되어 있고

만약에 셀렉트박스에서 년도와 월을 선택했을 경우에는 (코드22) 즉, sYear 과 sMonth 가 null 이 아닐 경우에는

현재의 날짜로 설정되어 있는 것에서 선택한 날짜로 변경을 해 준다. 

 

이제 기준이 되는 날짜를 정했으니 그에 맞게 년도와 월을 셀렉트 박스 옵션으로 구성해야 한다. 

만약 기준 날짜가 2021년 5월 이라면 년도는 2011 년부터 2031년까지 옵션이 들어가야 하고

월은 12월이 들어가야 한다. 

 

그런데 문제가 하나 생긴다. 셀렉트박스는 내가 선택한 값과 무관하게 첫 번째 옵션 값으로 다시 돌아가는 것이다.

(예를 들면 달력은 2021년 8월 달력인데 셀렉트 박스에는 2011년 1월이 선택되어버린다.)

아래의 예시를 보면!

 

나는 이렇게 3을 선택했는데 
이렇게 다시 1년으로 select box가 선택되어 있다. 

select box 의 onchange 속성으로 인해 변경이 일어나면 submit 해주는데, 문제는 다시 페이지가 처음의 상태로 돌아가는 것. 그래서  선택을 한 후에는 선택한 년, 또는 월의 셀렉트박스 옵션에 selected="selected" 속성을 해줘야 한다. 

 

위에서 설명한 내용과 동일한 내용이다. 

 

for 문을 돌면서 기준년도의 이전 10년과 이후 10년까지 총 20년의 옵션을 찍어낼 것인데

그 중에서 1. 셀렉트박스가 선택되지 않았고 옵션을 그리는 년도가 현재 년도라면 selected 속성을 준다.

2. 그게 아니고 셀렉트박스에서 년도를 선택했고 옵션을 그리는 년도가 선택한 년도라면 selected 속성을 준다.

3. 그 모든 경우가 아니라면 select 속성을 지정하지 않고 옵션을 그린다. 

 

아래서 할 월도 위와 비슷하다. 

 

이와 같이 처리해주면 셀렉트 박스 문제는 모두 처리가 된다. 

 

이제는 년도와 월을 기준으로 달력을 그릴 준비를 하는 단계이다. 

 참 많이도 했던 달력이지만 쉽게 익숙해지지도 않는 달력..

달력을 그리기 위해서는 해당 년도의 해당 월이 <1일이 어떤 요일에서 시작하는지 > 와 <몇 일로 이루어져있는지> 가 

궁금해서 1년 1월 1일부터 그 날짜까지의 일수를 구해서 7로 나눠서 요일을 얻어내고 

각 월 별 마지막 날짜로 구성된 배열을 만들어서 총 몇 일인지까지 얻어내는건데 (게다가 윤년까지 고려를 해야 한다)

 

캘린더 객체를 활용하면 이 세 줄의 코드로 저 모든 것을 해결할 수 있기는 하다,,, 하지만 오늘도 난 달력을 그린다. 

2021년 5월 기준으로 1일은 토요일에서 시작하므로 week 변수는 6일 것이고

for 문은 0부터 5까지 총 6번을 돌면서 공백을 채울 것이다. 

count 변수는 하나씩 증가하면서 마지막 금요일 공백을 채우고 나서는 6이 되어있을 것이다. 

이거는 int count 가 하나씩 증가하는 것을 보여주는 것 , 대괄호안에는 count 이다. 

 

우선 이렇게 개행을 하지 않고 쭉 그려보면 31일까지 그려진다. 개행을 하는 위치는 count==7 또는 14 ,,, 7의 배수일때

 

따라서 count%7==0 일 때마다 개행을 해주는 코드를 삽입해주면 개행이 된다.

그런데 개행을 해야 할 차례인데 마지막날이면, 예를들어 토요일이 31일이면 개행을 해주면 안되기 때문에 

조건문에 i != lastDay 라는 조건도 넣어준다. 개행을 하고 count 에 0을 대입하는 이유는 아래서 설명할 것이다. 

달력을 그렸는데 마지막 날짜 뒤로 길게 공백이 생기기 때문에 그곳에도 칸을 만들어줘야 한다.

count=0 으로 한 이유가 여기있다.

위의 달력 예시로 보면 30은 count가 0일 것이고 31일 은 count 가 1일 것이다

count 가 6이 될 때까지 칸을 그려야하는 것을 알 수 있다

만약 count에 0을 대입하지 않고 날짜를 그릴때마다 증가했으면 count는 31을 그릴 때 36이 되어있을 것이고 그러면 뒤에 공백이 있는지 있으면 얼마나 있는지 파악을 못하게 될 것이다,. 

 

 

 

 

바디 영역은 이러하다. 뒤에서 그려줬던 년도와 월의 셀렉트박스 옵션들, 그리고 그려놨던 달력 calStr 

이 정도가 전부이다. 

 

여기서 일요일과 토요일에 해당하는 칸들에는 색을 다르게 주고 현재 날짜에 해당하는 칸은 강조하는 색을 넣을 수도 있지만 그것은 다음에 알아보기로,, ㅎㅎ

 

 

<%@page import="java.util.Calendar"%>
<%@ page contentType="text/html; charset=UTF-8"%>
<%
	String sYear  = request.getParameter("year"); //페이지 최초 요청 시  null 이다.
	String sMonth = request.getParameter("month"); //페이지 최초 요청 시  null 이다.
	
	
	
	// 캘린터 객체 생성
	Calendar  cal = Calendar.getInstance();	
	// 
	
	int nowYear = cal.get(Calendar.YEAR); //현재년도 (ex. 2021
	int nowMonth = cal.get(Calendar.MONTH)+1;//현재달 (ex. 5
	int nowDay = cal.get(Calendar.DAY_OF_MONTH);//현재 날짜 (ex.11
			
	// 페이지 최초 요청 시 현재 날짜가 보이도록 해주는 코드
	int selectYear = nowYear;
	int selectMonth = nowMonth;
	
	
	// 페이지 최초 요청이 아닐 경우 , 즉 클라이언트가 년도와 월을 셀렉트박스에서 선택했을 경우
	if (sYear != null || sMonth != null)
	{
		selectYear = Integer.parseInt(sYear);
		selectMonth = Integer.parseInt(sMonth);
		
	}
	
	
	// 확인한 날짜로 년도 selectOption 을 구성
	//<option value = "2011">2011</option>
	//<option value = "2012">2012</option>
	//<option value = "2013">2013</option>
	//						:
	//<option value = "2021">2021</option>
	//						:
	//<option value = "2029">2029</option>
	//<option value = "2030">2030</option>
	//<option value = "2031">2031</option> 이렇게 그려야 한다. 
	
	
	// 여기서 문제가 생기는 부분은 select box 를 선택하면 그 데이터를 전송해준 뒤 바로 새로 페이지가 요청이 되면서
	// select box 의 첫번째 선택지로 넘어가버린다. 예를 들어, 2022년을 선택했는데 제일 첫 번째 값인 2011 년이 선택이 된다.
	// 아래 두 개의 for문은 이러한 문제를 방지하기 위한 코드이다. 
	// 이 처리 이후에는 2022 년을 선택하면 select box 에는 2022년이 계속 선택되어있을 것이다. 
	

	
	String yOptions = ""; // 셀렉트 박스 년도 옵션
	for (int year=(selectYear-10); year<=(selectYear+10); year++)
	{	
		//경우에 따라서는 selected 가 들어가야 한다.
		// 첫 번째 경우, 페이지 최초 요청일 때는 sYear 는 null 이면서 현재 년도와 옵션값이 같을 때 
		if (sYear==null && year == nowYear)
			yOptions += "<option value ='" + year + "' selected='selected'>" + year +"</option>";
		else if (sYear!=null && Integer.parseInt(sYear)==year)
		{
			yOptions += "<option value ='" + year + "' selected='selected'>" + year +"</option>";
		}
		else
		{
			yOptions += "<option value ='" + year + "'>" + year +"</option>";
		}

	}
	
	
	String mOptions = ""; // 셀렉트 박스 월 옵션 
	for (int month=1; month<=12; month++)
	{
		if (sMonth == null && month == nowMonth) //선택한 날짜가 없을 때 현재 월을 selected 되도록 한다. 
		{
			mOptions += "<option value ='" + month + "' selected='selected'>" + month +"</option>";
			
		}
		else if (sMonth != null && month==Integer.parseInt(sMonth)) //선택한 월이 있을 때는 그 월을 seleceted 되도록 한다.
		{
			mOptions += "<option value ='" + month + "' selected='selected'>" + month +"</option>";
		}
		else // 나머지 월의 경우라면 selected 되지 않도록 한다. 
		{
			
			mOptions += "<option value ='" + month + "'>" + month +"</option>";
		}	

	}
	
	//------------------<달력을 그리기 위한 준비 >---------------------------------------------------
	int [] months = {31,28,31,30,31,30,31,31,30,31,30,31};
	
	if (selectYear%4==0 && selectYear%100!=0 || selectYear%400==0) // 윤년일 때는 2월이 29일 이다.
	{
		months[1] = 29;
	}
	
	
	// 총 날수를 누적시킬 값
	int nalsu;
	
	
	// 요일 항목 배열 구성
	String[] weekName = {"일요일", "월요일", "화요일", "수요일", "목요일", "금요일", "토요일"};
	
	// 입력받은 년도의 이전 년도까지의 날 수 계산 (ex_ 2021년 5월 5일이면 2020년 12월 31일까지의 날짜)
	nalsu = (selectYear-1)*365 + (selectYear-1)/4 - (selectYear-1)/100 + (selectYear-1)/400; 
	// 4년짜리 윤년마다 빼고,, 100년마다는 아닌데 빼줬으니까 더해주고,, 400년마다는 빼지말아야하는데 뺏으니까 더해주고
	
	
	// 현재 월 또는 입력받은 월의 전 월의 31일 까지를 계산
	for (int i= 0; i<selectMonth-1; i++)
	{
		nalsu += months[i];
	}
	
	// 달력을 그리려면 현재 달, 또는 입력받은 달의 1일이 필요하므로 날 수를 하나 더해준다.
	nalsu ++;
	
	
	// 1일의 요일 변수
	int week = nalsu%7; /*1은 월요일 0은 일요일  */	
	int lastDay = months[selectMonth-1]; // 그 달에 총 몇 '일' 이 있는지 파악
	
	//-------------------------------------<달력그리기>-----------------------------------------------------
	
	String calStr = "";
	calStr += "<table border='1'>";
	calStr += "<tr>";
	
	for (int i=0; i<weekName.length; i++)
	{
		if (i==0) //  일요일
		{
			calStr += "<th style='color:red;'>" + weekName[i] + "</th>";
			
		}
		else if (i==6) // 토요일
		{
			calStr += "<th style='color:blue;'>" + weekName[i] +  "</th>";
					
		}
		else // 나머지 요일
		{
			calStr += "<th>" + weekName[i] + "</th>";
		}
		
	}
	
	calStr += "</tr>";


	
	
	calStr += "<tr>";
	
	
	// 칸을 하나씩 더해줄때마다 하나씩 늘려줄 변수
	int count=0;
	
	// 맨 처음 공백 채우기 
	
	for(int i=0;i<week;i++)
	{
		calStr += "<th></th>";
		count++;
	}
	
	
	// 1일부터 마지막날까지 채우기
	for(int i=1; i<= lastDay; i++)
	{
		calStr += "<th>"+ i + "</th>";
		count++;
		if (count%7==0 && i != lastDay)
		{
			calStr +="</tr><tr>";
			count=0; // ★★★★ 
		}
	}
	
	
 	//빈 공백 채우기
	while (count<7) 
	{
		calStr += "<td>*</td>";
		count++;
		
		
	}
	calStr += "</table>";		
	
	

%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PrintCalendar.jsp</title>
<script type="text/javascript">
	
	function submit(obj) //  obj는 form 의 객체
	{
		obj.submit();
	}

</script>
</head>
<body>



<!--  
	● 데이터 송수신 실습  07
	- 달력을 출력하는 JSP 페이지를 구성한다.
	- 연도와 월을 입력받아 화면에 출력해주는 형태의 페이지로 구성한다.
	- 단, submit 버튼 없이 이벤트 처리를 한다.
	- 전송한 내용을 수신해서 출력해주는 형태의 페이지로 구성한다.(단독 페이지)
	- 연도 구성은 현재 년도 기준 이전 10년 ,이후 10년으로 구성한다.
	- 월은 1부터 12월 까지로 구성한다.
	
	[2021▼]년 [5▼]월
	================
	================
	
	- 연도 select box 나 월 selectbox 내용 변화 시
		해당 년 월의 달력을 출력해주는 형태의 페이지로 구성한다.
		- 현재 연도/월 확인하는 과정에서 Calendar 클래스를 활용한다.
		
		- 사용자의 최초 요청 주소는 http://localhost:8090/WebApp07/SendAndReceive07.jsp
		로 한다.
		
		● SendAndReceive07.jsp
		

-->
<div>
	<h1>원하는 년도와 달을 선택하세요! </h1>
	<hr>
</div>

<div>
   <form action="" method="post">
      <select id="year" name ="year" onchange="submit(this.form)"> <!-- submit 버튼이 없으므로 여기에 이벤트 핸들러를 달아주어야 함 
      											
      																여기서 this.form 은 select 박스를 포함하고 있는 form 엘리먼트이다.	
      																스크립트 단에서 함수를 통해서 form의 데이터를 .submit() 해주면 
      																받는 주체는 자기 자신 페이지이다. 그것을 name 속성으로 스크립트릿 영역에서
      																받아준다.-->
      <%=yOptions %>
      </select>년
      <select id="month" name="month" onchange="submit(this.form)">
      <%=mOptions %>
      </select>월  
      

   </form>
</div>



<br><br>
<div>
<!--달력을 그리게 될 지점  -->
선택된 날짜 : <%=sYear %>년<%=sMonth %>월 <br><br><br>
<%=calStr %>

</div>




</body>
</html>