[Java] SpringBoot 프로젝트 : LocalDate 활용 일주일 누적 시간 구하기
구현하고자 했던 기능 정의
- 로그인 한 회원의 마이페이지에 해당 회원의 주간 공부시간을 일별 그래프로 보여준다.
- 해당 주(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>
잘 이용할 줄 몰라서 직접 띄워보며 몇 가지 값들만 조정했다.
[결과]
데이터 있을 때
데이터 없을 때