ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] SpringBoot 프로젝트 : LocalDate 활용 일주일 누적 시간 구하기
    프로젝트/기능 정리 2023. 6. 5. 15:55

    구현하고자 했던 기능 정의

    • 로그인 한 회원의 마이페이지에 해당 회원의 주간 공부시간을 일별 그래프로 보여준다.
    • 해당 주(ex. 2023.06.05(월)~2023.06.11(일))가 지나면 다음 주(ex. 06.12(월)~06.18(일)) 날짜가 그래프 하단에 표시된다.
    • 회원이 하루에 입/퇴실을 여러번 한 기록 모두 그 날 하루의 누적 시간에 포함된다.
    • DB에 회원의 총 누적 공부 시간과 일별 공부시간은 초기화 하지 않는다.
    • 정리하면, 주가 바뀔 때 마다 DB에 저장된 시간 관련 데이터를 초기화 하지 않고 해당하는 주 데이터만 불러와서 그래프에 보여준다.

     

    [JAVA_controller]

    일주일에 해당하는 날짜와 일별 누적 시간을 담아둘 배열을 선언했다.

    String[] setThisWeek = new String[7];
    Integer[] setTotalTime_thisWeek = new Integer[7];

    LocalDate 클래스를 통해 오늘 날짜를 저장해뒀다.

    LocalDate now = LocalDate.now();

    마찬가지 LocalDate 클래스를 통해 이번 주 월요일과 다음 주 월요일을 저장해뒀다.

    LocalDate setThisMonday = now.with(DayOfWeek.MONDAY);
    LocalDate setNextMonday = setThisMonday.plusDays(7);

    with 메소드를 사용하면 LocalDate의 인스턴스를 변경하지 않고 파라미터에 의해 조정된 값을 리턴해준다.

     

    now에 담긴 오늘 날짜를 기준으로 오늘이 무슨 요일이든 이번 주 월요일의 날짜를 찾고 싶어 DayOfWeek.MONDAY를 넣어줬다.

     

    plusDays 메소드는 메소드를 호출한 객체에 전달받은 파라미터(여기선 7)'일'만큼 더한 LocalDate 객체를 리턴해준다.

     

    정리하면, 오늘 날짜 기준으로 이번 주 월요일 날짜를 찾고, 찾은 이번 주 월요일을 기준으로 7일 후인 다음주 월요일 날짜를 찾아 각각 LocalDate 객체로 저장해둔 것이다.

     

     

    이제 선언해둔 날짜를 저장할 배열에 이번 주 월요일 날짜를 기준으로 반복문을 사용해 값을 할당해줬다.

    for(int i = 0; i < setThisWeek.length; i++) {
    	setThisWeek[i] = setThisMonday.plusDays(i).toString();
    }
    //결과
    //2023-06-05 2023-06-06 2023-06-07 2023-06-08 2023-06-09 2023-06-10 2023-06-11

    다음은 이 날짜 배열을 이용해 DB에서 날짜에 해당하는 공부시간을 불러오기 위해 반복문을 사용했다.

    for(int i = 0; i < setTotalTime_thisWeek.length; i++) {
    	if(i == setTotalTime_thisWeek.length - 1) {
    		setTotalTime_thisWeek[i] = mypageService.selectSumTotalTimeForGraph(setThisWeek[i], setNextMonday.toString(), user.getMem_num());
    	}else {
    		setTotalTime_thisWeek[i] = mypageService.selectSumTotalTimeForGraph(setThisWeek[i], setThisWeek[i+1], user.getMem_num());
    	}
    }

    selectSumTotalTimeForGraph는 세 개의 파라미터를 받는데 앞 두 개는 검색할 시작 날짜와 끝 날짜(ex. 2023.01.01, 2023.01.02이면 1월 1일 0시 0분에서 23시 59분까지 범위)이고, 마지막 한 개는 검색 할 회원의 회원 번호이다.

     

    if문으로 마지막 인덱스 값일 때 두 번째 파라미터를 위에서 구한 setNextMonday로 넘겨준 이유는 이번 주 날짜들을 저장해둔 setThisWeek 배열에 담긴 마지막 날짜가 일요일이므로 다음 주 월요일 데이터를 배열 내에서 인덱스로 찾을 수 없기 때문이다(값을 가져와서 똑같이 plusDays(1)을 한 뒤에 가져와도 되지만 어쨌든 조건문을 써야한다고 생각했다).

     

    이렇게 데이터를 모두 채운 두 배열은 model에 담아서 jsp로 보내준다.

    //한 주 날짜 담은 배열 넘겨주기
    model.addAttribute("week", setThisWeek);
    //날짜별 시간 담은 배열 넘겨주기
    model.addAttribute("time", setTotalTime_thisWeek);

    jsp에서 모델에 담긴 week, time 변수에 접근해서 인덱스로 각 값을 가져오면 끝이다.

     

     

    [JAVA_service]

    위에서 selectSumTotalTimeForGraph는 mapper(dao)에 선언해두고 controller에서 service를 주입받아 사용했다.

     

    크게 흐름을 정리해본다.

    [mapper]

    기본적으로 하나의 파라미터만 받을 수 있지만 @Param을 이용해서 세 개의 파라미터를 받을 수 있도록 했다.

     

    sql문은 받은 시작 날짜와 끝 날짜 사이이면서 회원 번호가 전달받은 파라미터와 일치하는 행들의 total_time을 모두 더한 값을 반환하도록 작성했다.

     

    여기서 total_time은 회원이 입실 후 퇴실한 사이 시간을 초단위로 저장해둔 DB내 열이다.

    //날짜 1, 날짜 2 받아서 고 사이에 입퇴실 내역 sum 구하기
    @Select("SELECT sum(total_time) FROM seat_detail WHERE in_time BETWEEN TO_DATE(#{weekStart}) AND TO_DATE(#{weekEnd}) AND mem_num = #{mem_num}")
    public int selectSumTotalTimeForGraph(@Param(value = "weekStart") String weekStart, @Param(value = "weekEnd") String weekEnd, @Param(value = "mem_num") Integer mem_num);

    [service]

    public interface MypageService{
    	public int selectSumTotalTimeForGraph(String weekStart, String weekEnd, Integer mem_num);
    }

    [serviceImpl]

    @Service
    @Transactional
    public class MypageServiceImpl implements MypageService{
    	@Autowired
    	private MypageMapper mypageMapper;
        
    	@Override
    	public int selectSumTotalTimeForGraph(String weekStart, String weekEnd, Integer mem_num) {
    		Integer result;
    		try {
    			result = mypageMapper.selectSumTotalTimeForGraph(weekStart, weekEnd, mem_num);
    			return result;
    		}catch(Exception e) {
    			result = 0;
    			return result;
    		}
    	}
    }

    회원의 입/퇴실 내역이 없으면 DB에서 찾을 수 없으므로 try catch문을 사용해 null일 경우 결과를 0으로 세팅해줬다.

    [controller]

    @Controller
    public class MypageController {
    	@Autowired
    	private MypageService mypageService;
        
        //이하 시간 구하는 부분
    }

    이런 흐름으로 컨트롤러에서 selectSumTotalTimeForGraph를 호출할 수 있게 됐다.

     

     

    [JSP]

    jsp에서는 Chart.js를 이용해서 그래프를 그렸다.

    <div>
    	<div class ="mypage-title">
    	<h4 class = "sum-title">주간공부시간</h4>
    	</div>
    	<hr class = "horizontal-line">
    		<canvas id = "line-chart" width = "1040" height = "300"></canvas>
    		<script type="text/javascript">
    		var mon = ('${time[0]}'/3600 <=  0) ? 0 : '${time[0]}' / 3600;
    		var tue = ('${time[1]}'/3600 <=  0) ? 0 : '${time[1]}' / 3600;
    		var wed = ('${time[2]}'/3600 <=  0) ? 0 : '${time[2]}' / 3600;
    		var thu = ('${time[3]}'/3600 <=  0) ? 0 : '${time[3]}' / 3600;
    		var fri = ('${time[4]}'/3600 <=  0) ? 0 : '${time[4]}' / 3600;
    		var sat = ('${time[5]}'/3600 <=  0) ? 0 : '${time[5]}' / 3600;
    		var sun = ('${time[6]}'/3600 <=  0) ? 0 : '${time[6]}' / 3600;
    		new Chart(document.getElementById('line-chart'), {
    			type : 'line',
    			data : {
    				labels : ['${week[0]}', '${week[1]}', '${week[2]}','${week[3]}', '${week[4]}', '${week[5]}','${week[6]}'],
    				datasets : [{
    					data : [mon, tue, wed, thu, fri, sat, sun],
    					label : '내 공부시간',
    					borderColor : '#E65962',
    					backgroundColor: '#E65962',
    					pointStyle : false,
    					fill : false,
    					tension : 0.3,
    					borderWidth : 3,
    				}]},
    			options : {
    				scales :{
    					y :{
    						ticks :{
    							display : true,
    							stepSize : 0.5,
    						},
    						min : 0,
    						suggestedMin : 0
    					},
    					x : {
    						grid: {
    							display : false
    						}
    					}
    				}
    			}
    		});
    	</script>
    </div>

    잘 이용할 줄 몰라서 직접 띄워보며 몇 가지 값들만 조정했다.

     

     

    [결과]

    데이터 있을 때

    데이터 없을 때

     

Designed by Tistory.