Spring으로 개발을 하다보면 다른 나라에서 서비스되는 웹 사이트도 개발을 해야하는 상황이 생기는데 이때 서로 다른 시간대를 가진 두 나라의 적용은 어떻게 해야할까?
동시에 두 나라에서 글을 작성을 한다고 해도 저장되는 시간은 각자 다르게 저장이 될 것이다. 이러한 문제점을 GMT라는 국제 표준시를 이용하여 해결해보자.
본인은 javascirpt로 utc와의 차이를 구하고 cookie에 담았고 날짜 정보가 필요한 부분에선 Spring의 Interceptor를 사용하여 cookie에 저장된 값을 posthandle을 사용하여 시간대를 맞춰주었다.
협정 세계시(프랑스어: Temps Universel Coordonné, 영어: Coordinated Universal Time) 또는 UTC(협정 세계표준시)는 1972년 1월 1일부터 시행된 국제 표준시이다.
UTC는 그리니치 평균시(GMT)에 기반하므로 GMT로도 불리기도 하는데, UTC와 GMT는 초의 소숫점 단위에서만 차이가 나기 때문에 일상에서는 혼용되어 사용된다. 기술적인 표기에서는 UTC가 사용된다.
대한민국은 UTC+0900을 사용한다.
가장 먼저 utc의 시간을 갖는 DB를 만들어보자. oralce을 기준으로 현재 utc의 시간을 저장해보자. Date라는 컬럼에
FROM_TZ(CAST(CURRENT_TIMESTAMP AS TIMESTAMP), 'UTC')
이런식으로 시간을 INSERT하였다.
우리 interceptor를 사용해야 하므로 sevlet에 저장해보자.
public class gmtInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
HttpSession session = request.getSession();
String naraSession = (String)session.getAttribute("naraLocal");
String localNara = (String)request.getParameter("localNara");
String num = (String)request.getParameter("num");
if(naraSession == null) {
if(localNara == null) {
response.sendRedirect("/time.do?num="+num);
}else {
session.setAttribute("naraLocal", localNara);
}
}
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// 1차 방식
HttpSession session = request.getSession();
String nara = (String)session.getAttribute("naraLocal");
Map<String, Object> model = modelAndView.getModel();
gmtDTO dto = (gmtDTO) model.get("content");
if(dto !=null && nara !=null) {
int timeDif = kstDitDif(request);
if(nara.equals("ko")) {
String updateDate = dateUpdate(timeDif,dto);
model.put("prev", dto.getReddate());
dto.setRegdate(updateDate);
}
model.put("dto",dto);
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
public String dateUpdate(int dif,gmtDTO dto) throws ParseException {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
Date date = format.parse(dto.getReddate());
Calendar cal = Calendar.getInstance();
cal.setTime(date);
cal.add(Calendar.HOUR_OF_DAY, dif);
String strDate = format.format(cal.getTime());
return strDate;
}
public int kstDitDif(HttpServletRequest request) {
Cookie[] list = request.getCookies();
for(Cookie cookie:list) {
if(cookie.getName().equals("naraDifTime")) {
return Integer.parseInt(cookie.getValue());
}
}
return 0;
}
}
view.do 매핑을 타게되면 해당 interceptor를 오게 설정해놨다.
prehandle을 보게되면 session을 체크하고 없다면 session에 저장 될 parameter까지 확인하여 둘다 없으면 전혀 다른 url로 이동시키게 된다. 해당 주소가 utc의 시간차와 현재 클라이언트의 language까지 구하는 javascript가 잇는 페이지이다. 아직까진 prehandle만 보면 된다. 이어서 해당 페이지로 이동해보자.
<script>
var nara = '${localNara}';
var num = '${num}';
var value = document.cookie.match('(^|;) ?naraDifTime=([^;]*)(;|$)');
if(value == null){
setCookie();
}
function setCookie(){
var currentTime = new Date();
var timezoneOffsetInMinutes = currentTime.getTimezoneOffset();
var timeDifference = timezoneOffsetInMinutes / 60;
// 시간 차이를 음수 또는 양수로 변환
if (timeDifference >= 0) {
timeDifference = -timeDifference;
}else {
timeDifference = Math.abs(timeDifference);
}
document.cookie = 'naraDifTime=' + timeDifference;
}
if(nara === ''){
nara = navigator.language.substr(0,2);
window.location.href = '/view.do?localNara='+nara+'&num='+num;
}
</script>
해당 javascript를 천천히 보게 되면 localNara라는 값과 num이라는 변수를 저장하고있는데 intereceptor에서 넘어올때 모습을 보게 되면 num값만 갖게 된다. 즉 nara는 null이 된다. 이어 cookie의 값을 확인하고 값이 비엇다면 utc와 현재 사용중인 시간대의 차이를 구하여 'naraDifTime'이라는 이름의 쿠키를 저장한 모습이다. 마지막으로 nara라는 변수가 비었다. navigator.language를 사용하여 현재 사용중인 나라의 언어를 구하여 맨 처음 우리가 이동하려고 했던 view페이지로 localNara와 num을 갖고 이동을 한다.
@RequestMapping(value="/view.do")
public String view(HttpServletRequest res,HttpSession session, gmtDTO dto, Model model,@RequestParam(required = false) String localNara) {
dto = gmtservice.getOneContent(dto.getNum());
model.addAttribute("content", dto);
return "view";
}
여기선 사실 별게 없다 num을 갖고 게시물을 꺼내고 model에 담아 jsp로 이동을 하게 되는데 마지막으로 posthandle을 거치게 된다.
해당 posthandle을 보게 되면 session에 저장된 localNara를 꺼내고 controller에 저장된 content를 꺼내고 두 값이 존재할경우 cookie에 저장된 시간차를 꺼내고 content객체의 날짜를 꺼내어 다시 model에 put하여 해당 jsp페이지로 이동을 한다.
이렇게 간단하게 interceptor와 gmt를 이용하여 각 나라의 시간을 맞추는 방법을 알아봤는데 아직 0년차 개발자의 입장에선 상당이 어려웠고 생각을 정리하느라 남들이 볼 땐 멍때리는 모습을 많이 봤을 것이다..
나중에 추후 실무에서 적용할 땐 좀 더 프로세스를 잘짜서 재사용 해야겠다.