瀏覽代碼

new interceptor add

shjung 3 年之前
父節點
當前提交
f2b2dfccbd

+ 1 - 1
src/main/java/com/its/op/interceptor/LoggingAspect.java → src/main/java/com/its/op/aop/LoggingAspect.java

@@ -1,4 +1,4 @@
-package com.its.op.interceptor;
+package com.its.op.aop;
 
 import lombok.extern.slf4j.Slf4j;
 import org.aspectj.lang.ProceedingJoinPoint;

+ 10 - 5
src/main/java/com/its/op/controller/its/LoginController.java

@@ -17,6 +17,7 @@ import org.springframework.web.servlet.ModelAndView;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
 
 @Slf4j
 @RequiredArgsConstructor
@@ -71,13 +72,13 @@ public class LoginController {
     @GetMapping({"/logout.do"})
     public ModelAndView getLogout(HttpServletRequest request, HttpServletResponse response) {
         Cookie[] cookies = request.getCookies();
-        log.error("{}", cookies.length);
-        for (int ii = 0; ii < cookies.length; ii++) {
-            log.error("{}, {}", cookies[ii].getName(), cookies[ii].getValue());
-        }
+//        log.error("{}", cookies.length);
+//        for (int ii = 0; ii < cookies.length; ii++) {
+//            log.error("{}, {}", cookies[ii].getName(), cookies[ii].getValue());
+//        }
         String encUserId = "";
         String loginHms = "";
-        if (cookies!= null && cookies.length > 0) {
+        if (cookies != null && cookies.length > 0) {
             try {
                 encUserId = CookieUtils.getCookie(request, WebMvcConfig.USER_UUID);
                 loginHms = CookieUtils.getCookie(request, WebMvcConfig.USER_TIME);
@@ -102,6 +103,10 @@ public class LoginController {
             expiredCookie(response, WebMvcConfig.USER_TIME);
             new SecurityContextLogoutHandler().logout(request, response, auth);
         }
+        HttpSession session = request.getSession(false);
+        if (session != null) {
+            session.invalidate();   // session remove
+        }
         return new ModelAndView("forward:/application/login/login.html");
     }
 

+ 0 - 51
src/main/java/com/its/op/interceptor/ApiHandlerInterceptor.java

@@ -1,51 +0,0 @@
-package com.its.op.interceptor;
-
-import com.its.op.security.WebMvcConfig;
-import com.its.utils.CookieUtils;
-import lombok.extern.slf4j.Slf4j;
-import org.apache.commons.lang.StringUtils;
-import org.springframework.lang.Nullable;
-import org.springframework.stereotype.Component;
-import org.springframework.web.servlet.HandlerInterceptor;
-import org.springframework.web.servlet.ModelAndView;
-
-import javax.servlet.http.Cookie;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import javax.servlet.http.HttpSession;
-
-@Slf4j
-@Component
-public class ApiHandlerInterceptor implements HandlerInterceptor {
-
-    @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
-        Cookie[] cookies = request.getCookies();
-        String userId = "";
-        String loginHms = "";
-        if (cookies != null && cookies.length > 0) {
-            userId = CookieUtils.getCookie(request, WebMvcConfig.USER_UUID);
-            loginHms = CookieUtils.getCookie(request, WebMvcConfig.USER_TIME);
-        }
-        if (userId == null || "".equals(userId)) {
-        }
-        else {
-            userId = WebMvcConfig.decUserId(userId);
-        }
-
-        log.debug("START: Request URI: {}", request.getRequestURI());
-
-        if (!StringUtils.equalsIgnoreCase("GET", request.getMethod())) {
-            HttpSession session = request.getSession(false);
-            if (session == null) {
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
-        log.debug("..END: Request URI: {}", request.getRequestURI());
-    }
-
-}

+ 8 - 8
src/main/java/com/its/op/security/UserInfrVo.java

@@ -111,16 +111,16 @@ public class UserInfrVo implements UserDetails {
         else {
             roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
         }
-        log.error("getAuthorities: {}", roles.toString());
+        //log.error("getAuthorities: {}", roles.toString());
         return roles;
     }
 
     @Override
     public String getPassword() {
-        log.error("getPassword: {}", this.pwd);
+        //log.error("getPassword: {}", this.pwd);
         WebPasswordEncoder be = new WebPasswordEncoder();
         String pwd = be.encode(this.pwd);
-        log.error("getPassword: {}, encoded.", this.pwd);
+        //log.error("getPassword: {}, encoded.", this.pwd);
         return pwd;
     }
 
@@ -130,31 +130,31 @@ public class UserInfrVo implements UserDetails {
 //        log.error("{}", Thread.currentThread().getStackTrace()[1].toString());
 //        log.error("{}", Thread.currentThread().getStackTrace()[2].toString());
 //        log.error("{}", Thread.currentThread().getStackTrace()[3].toString());
-        log.error("getUsername: {}, {}.{}", this.userId, Thread.currentThread().getStackTrace()[2].getClassName(), Thread.currentThread().getStackTrace()[2].getMethodName());
+        //log.error("getUsername: {}, {}.{}", this.userId, Thread.currentThread().getStackTrace()[2].getClassName(), Thread.currentThread().getStackTrace()[2].getMethodName());
         return this.userId;
     }
 
     @Override
     public boolean isAccountNonExpired() {
-        log.error("isAccountNonExpired");
+        //log.error("isAccountNonExpired");
         return true;
     }
 
     @Override
     public boolean isAccountNonLocked() {
-        log.error("isAccountNonLocked");
+        //log.error("isAccountNonLocked");
         return true;
     }
 
     @Override
     public boolean isCredentialsNonExpired() {
-        log.error("isCredentialsNonExpired");
+        //log.error("isCredentialsNonExpired");
         return true;
     }
 
     @Override
     public boolean isEnabled() {
-        log.error("isEnabled: {}", StringUtils.equalsIgnoreCase("N", this.delYn));
+        //log.error("isEnabled: {}", StringUtils.equalsIgnoreCase("N", this.delYn));
         return StringUtils.equalsIgnoreCase("N", this.delYn);
     }
 

+ 1 - 1
src/main/java/com/its/op/security/WebLoginService.java

@@ -22,7 +22,7 @@ public class WebLoginService implements UserDetailsService {
 
     @Override
     public UserDetails loadUserByUsername(String userId) throws UsernameNotFoundException {
-        log.info("loadUserByUsername: {}", userId);
+        //log.info("loadUserByUsername: {}", userId);
         Optional<TbUserInfr> optUserInfr = this.userRepo.findById(userId);
         TbUserInfr userInfr = optUserInfr.orElseThrow(() -> new UsernameNotFoundException(userId + " 을(를) 찾을 수 없습니다."));
         return userInfr.toVo();

+ 12 - 8
src/main/java/com/its/op/security/WebLoginSuccessHandler.java

@@ -19,7 +19,6 @@ import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import java.io.IOException;
 import java.util.ArrayList;
-import java.util.Enumeration;
 import java.util.List;
 
 @Slf4j
@@ -62,7 +61,7 @@ public class WebLoginSuccessHandler implements AuthenticationSuccessHandler {
                 .build();
         this.cnncHsRepo.insertData(cnncHs.getLoginHms(), cnncHs.getUserId(), cnncHs.getLogoutHms());
 
-        log.info("cnncHs: {}, {}", cnncHs.getUserId(), cnncHs.getLoginHms());
+        //log.info("cnncHs: {}, {}", cnncHs.getUserId(), cnncHs.getLoginHms());
 
         request.getSession().setAttribute(WebMvcConfig.USER_UUID, WebMvcConfig.encUserId(cnncHs.getUserId()));
         request.getSession().setAttribute(WebMvcConfig.USER_TIME, cnncHs.getLoginHms());
@@ -88,10 +87,13 @@ public class WebLoginSuccessHandler implements AuthenticationSuccessHandler {
 //        }
 
         // 세션 Attribute 확인
-        Enumeration<String> list = request.getSession().getAttributeNames();
-        while (list.hasMoreElements()) {
-            log.info("Attribute: {}", list.nextElement());
-        }
+//        Enumeration<String> list = request.getSession().getAttributeNames();
+//        while (list.hasMoreElements()) {
+//            log.info("Attribute: {}", list.nextElement());
+//            //Attribute: TIME
+//            //Attribute: UUID
+//            //Attribute: SPRING_SECURITY_CONTEXT
+//        }
         clearAuthenticationAttributes(request);
         response.sendRedirect(uri);
     }
@@ -102,9 +104,11 @@ public class WebLoginSuccessHandler implements AuthenticationSuccessHandler {
      */
     protected void clearAuthenticationAttributes(HttpServletRequest request) {
         HttpSession session = request.getSession(false);
-        log.error("clearAuthenticationAttributes: {}", session);
-        if (session == null)
+        //log.error("clearAuthenticationAttributes: {}", session);
+        if (session == null) {
+            log.warn("session already cleared.");
             return;
+        }
 
         session.removeAttribute(WebAttributes.AUTHENTICATION_EXCEPTION);
     }

+ 15 - 7
src/main/java/com/its/op/security/WebMvcConfig.java

@@ -1,9 +1,15 @@
 package com.its.op.security;
 
-import com.its.op.interceptor.ApiHandlerInterceptor;
+import com.its.op.security.interceptor.ApiInterceptor;
+import com.its.op.security.interceptor.LoggerInterceptor;
+import com.its.op.security.interceptor.SessionTimerInterceptor;
+import com.its.op.security.interceptor.UserInterceptor;
 import lombok.AllArgsConstructor;
 import org.springframework.context.annotation.Configuration;
-import org.springframework.web.servlet.config.annotation.*;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 
 @AllArgsConstructor
 @Configuration
@@ -12,17 +18,19 @@ public class WebMvcConfig implements WebMvcConfigurer {
     public static final String USER_UUID = "UUID";
     public static final String USER_TIME = "TIME";
 
-    private final ApiHandlerInterceptor apiHandlerInterceptor;
-
     /**
      * Controller Handler 인터셉서 등록
      * @param registry
      */
     @Override
     public void addInterceptors(InterceptorRegistry registry) {
-        registry.addInterceptor(this.apiHandlerInterceptor)
-                .addPathPatterns("/api/**")     // API Controller interceptors
-                .excludePathPatterns("/facility/**", "/wall/**") // 해당 경로는 인터셉터가 가로채지 않는다.
+        registry.addInterceptor(new SessionTimerInterceptor());
+        registry.addInterceptor(new LoggerInterceptor());
+        registry.addInterceptor(new UserInterceptor());
+
+        registry.addInterceptor(new ApiInterceptor())
+                .addPathPatterns("/api/**")                         // API Controller interceptors
+                .excludePathPatterns("/facility/**", "/wall/**")    // 해당 경로는 인터셉터가 가로채지 않는다.
                 ;
     }
 

+ 3 - 3
src/main/java/com/its/op/security/WebPasswordEncoder.java

@@ -13,7 +13,7 @@ public class WebPasswordEncoder implements PasswordEncoder {
         if (rawPassword == null) {
             throw new IllegalArgumentException("rawPassword cannot be null");
         }
-        log.error("encode: {}", rawPassword.toString());
+        //log.error("encode: {}", rawPassword.toString());
         return rawPassword.toString();
     }
 
@@ -29,13 +29,13 @@ public class WebPasswordEncoder implements PasswordEncoder {
             log.warn("Empty encoded password");
             return false;
         }
-        log.error("matches: {}, {}, {}", rawPassword.toString(), encodedPassword, StringUtils.equals(rawPassword.toString(), encodedPassword));
+        //log.error("matches: {}, {}, {}", rawPassword.toString(), encodedPassword, StringUtils.equals(rawPassword.toString(), encodedPassword));
         return StringUtils.equals(rawPassword.toString(), encodedPassword);
     }
 
     @Override
     public boolean upgradeEncoding(String encodedPassword) {
-        log.error("upgradeEncoding: {}", encodedPassword);
+        //log.error("upgradeEncoding: {}", encodedPassword);
         if (encodedPassword == null || encodedPassword.length() == 0) {
             log.warn("Empty encoded password");
             return false;

+ 43 - 0
src/main/java/com/its/op/security/interceptor/ApiInterceptor.java

@@ -0,0 +1,43 @@
+package com.its.op.security.interceptor;
+
+import com.its.op.security.WebMvcConfig;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang.StringUtils;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+@Slf4j
+public class ApiInterceptor implements HandlerInterceptor {
+
+    /**
+     * Executed before actual handler is executed
+     **/
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        // @CookieValue 를 컨트롤러에 추가해야함. (..., @CookieValue(value = "REMEMBER", required = false) Cookie rCookie)
+        log.info("START: Request URI: {}", request.getRequestURI());
+
+        HttpSession session = request.getSession(false);
+        if (session == null) {
+            log.error("로그인 하지 않은 사용자가 API(POST/PUT/DELETE)에 접근함.");
+            if (!StringUtils.equalsIgnoreCase("GET", request.getMethod())) {
+                // GET Method 를 제외한 Request 제한할 경우.... ==> Web Security 에서 처리함.
+                //return false;
+            }
+        }
+        else {
+            String encUserId = (String)session.getAttribute(WebMvcConfig.USER_UUID);
+            String userId = "";
+            if (!"".equals(encUserId)) {
+                userId = WebMvcConfig.decUserId(encUserId);
+            }
+            log.info("Session: {}", userId);
+        }
+
+        return true;
+    }
+
+}

+ 76 - 0
src/main/java/com/its/op/security/interceptor/LoggerInterceptor.java

@@ -0,0 +1,76 @@
+package com.its.op.security.interceptor;
+
+import com.google.common.base.Strings;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.lang.Nullable;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.Enumeration;
+
+@Slf4j
+public class LoggerInterceptor implements HandlerInterceptor {
+
+    /**
+     * Executed before actual handler is executed
+     **/
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        log.info("[preHandle][" + request + "]" + "[" + request.getMethod() + "]" + request.getRequestURI() + getParameters(request));
+        return true;
+    }
+
+    /**
+     * Executed before after handler is executed
+     **/
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
+        log.info("[postHandle][" + request + "]");
+    }
+
+    /**
+     * Executed after complete request is finished
+     **/
+    @Override
+    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
+        if (ex != null)
+            ex.printStackTrace();
+        log.info("[afterCompletion][" + request + "][exception: " + ex + "]");
+    }
+
+    private String getParameters(final HttpServletRequest request) {
+        final StringBuffer posted = new StringBuffer();
+        final Enumeration<?> e = request.getParameterNames();
+        if (e != null)
+            posted.append("?");
+        while (e != null && e.hasMoreElements()) {
+            if (posted.length() > 1)
+                posted.append("&");
+            final String curr = (String) e.nextElement();
+            posted.append(curr)
+                    .append("=");
+            if (curr.contains("password") || curr.contains("answer") || curr.contains("pwd")) {
+                posted.append("*****");
+            } else {
+                posted.append(request.getParameter(curr));
+            }
+        }
+
+        final String ip = request.getHeader("X-FORWARDED-FOR");
+        final String ipAddr = (ip == null) ? getRemoteAddr(request) : ip;
+        if (!Strings.isNullOrEmpty(ipAddr))
+            posted.append("&_psip=" + ipAddr);
+        return posted.toString();
+    }
+
+    private String getRemoteAddr(final HttpServletRequest request) {
+        final String ipFromHeader = request.getHeader("X-FORWARDED-FOR");
+        if (ipFromHeader != null && ipFromHeader.length() > 0) {
+            log.debug("ip from proxy - X-FORWARDED-FOR : " + ipFromHeader);
+            return ipFromHeader;
+        }
+        return request.getRemoteAddr();
+    }
+}

+ 52 - 0
src/main/java/com/its/op/security/interceptor/SessionTimerInterceptor.java

@@ -0,0 +1,52 @@
+package com.its.op.security.interceptor;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.lang.Nullable;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+@Slf4j
+public class SessionTimerInterceptor implements HandlerInterceptor {
+
+    private static final long MAX_INACTIVE_SESSION_TIME = 5 * 10000;
+
+    private HttpSession session;
+
+    /**
+     * Executed before actual handler is executed
+     **/
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        log.info("Pre handle method - check handling start time");
+        long startTime = System.currentTimeMillis();
+        request.setAttribute("executionTime", startTime);
+        if (UserInterceptor.isUserLogged()) {
+            session = request.getSession();
+            log.info("Time since last request in this session: {} ms", System.currentTimeMillis() - request.getSession()
+                    .getLastAccessedTime());
+            if (System.currentTimeMillis() - session.getLastAccessedTime() > MAX_INACTIVE_SESSION_TIME) {
+                log.warn("Logging out, due to inactive session");
+                SecurityContextHolder.clearContext();
+                request.logout();
+                response.sendRedirect("/spring-security-rest-full/logout");
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Executed before after handler is executed
+     **/
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
+        log.info("Post handle method - check execution time of handling");
+        long startTime = (Long) request.getAttribute("executionTime");
+        log.info("Execution time for handling the request was: {} ms", System.currentTimeMillis() - startTime);
+    }
+
+}

+ 89 - 0
src/main/java/com/its/op/security/interceptor/UserInterceptor.java

@@ -0,0 +1,89 @@
+package com.its.op.security.interceptor;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.lang.Nullable;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.servlet.HandlerInterceptor;
+import org.springframework.web.servlet.ModelAndView;
+import org.springframework.web.servlet.SmartView;
+import org.springframework.web.servlet.View;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+@Slf4j
+public class UserInterceptor implements HandlerInterceptor {
+
+    /**
+     * Executed before actual handler is executed
+     **/
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        if (isUserLogged()) {
+            addToModelUserDetails(request.getSession());
+        }
+        return true;
+    }
+
+    /**
+     * Executed before after handler is executed. If view is a redirect view, we don't need to execute postHandle
+     **/
+    @Override
+    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
+        if (modelAndView != null && !isRedirectView(modelAndView)) {
+            if (isUserLogged()) {
+                addToModelUserDetails(modelAndView);
+            }
+        }
+    }
+
+    /**
+     * Used before model is generated, based on session
+     */
+    private void addToModelUserDetails(HttpSession session) {
+        log.info("================= addToModelUserDetails ============================");
+        String loggedUsername = SecurityContextHolder.getContext()
+                .getAuthentication()
+                .getName();
+        session.setAttribute("username", loggedUsername);
+        log.info("user(" + loggedUsername + ") session : " + session);
+        log.info("================= addToModelUserDetails ============================");
+
+    }
+
+    /**
+     * Used when model is available
+     */
+    private void addToModelUserDetails(ModelAndView model) {
+        log.info("================= addToModelUserDetails ============================");
+        String loggedUsername = SecurityContextHolder.getContext()
+                .getAuthentication()
+                .getName();
+        model.addObject("loggedUsername", loggedUsername);
+        log.trace("session : " + model.getModel());
+        log.info("================= addToModelUserDetails ============================");
+
+    }
+
+    public static boolean isRedirectView(ModelAndView mv) {
+        String viewName = mv.getViewName();
+        if (viewName.startsWith("redirect:/")) {
+            return true;
+        }
+
+        View view = mv.getView();
+        return (view != null && view instanceof SmartView && ((SmartView) view).isRedirectView());
+    }
+
+    public static boolean isUserLogged() {
+        try {
+            return !SecurityContextHolder.getContext()
+                    .getAuthentication()
+                    .getName()
+                    .equals("anonymousUser");
+        } catch (Exception e) {
+            return false;
+        }
+    }
+}

+ 33 - 24
src/main/resources/mybatis/mapper/its/dashboard/DashboardMapper.xml

@@ -5,45 +5,54 @@
 
     <select id="findAllCmtrGradCountSttsLink" resultType="com.its.op.dto.its.dashboard.CmtrGradCountSttsDto">
         <![CDATA[
-        select prcn_dt,
-               sum(decode(cmtr_grad_cd,'LTC1', 1, 0)) as ltc1,
-               sum(decode(cmtr_grad_cd,'LTC2', 1, 0)) as ltc2,
-               sum(decode(cmtr_grad_cd,'LTC3', 1, 0)) as ltc3,
-               sum(decode(cmtr_grad_cd,'LTC0', 1, 0)) as ltc0,
+        select prcn_dt, sum(ltc1) as ltc1, sum(ltc2) as ltc2, sum(ltc3) as ltc3, sum(ltc0) as ltc0,
                0 as total, 0 as rate_ltc1, 0 as rate_ltc2, 0 as rate_ltc3, 0 as rate_ltc0
-        from tb_link_traf_hs
-        where prcn_dt >= to_char(sysdate-1/24, 'YYYYMMDDHH24MISS')
-        group by prcn_dt, cmtr_grad_cd
+        from (select prcn_dt,
+                     sum(decode(cmtr_grad_cd,'LTC1', 1, 0)) as ltc1,
+                     sum(decode(cmtr_grad_cd,'LTC2', 1, 0)) as ltc2,
+                     sum(decode(cmtr_grad_cd,'LTC3', 1, 0)) as ltc3,
+                     sum(decode(cmtr_grad_cd,'LTC0', 1, 0)) as ltc0
+              from tb_link_traf_hs
+              where prcn_dt >= to_char(sysdate-1/24, 'YYYYMMDDHH24MISS')
+              group by prcn_dt, cmtr_grad_cd
+             )
+        group by prcn_dt
         order by prcn_dt
         ]]>
     </select>
 
     <select id="findAllCmtrGradCountSttsIfsc" resultType="com.its.op.dto.its.dashboard.CmtrGradCountSttsDto">
         <![CDATA[
-        select prcn_dt,
-               sum(decode(cmtr_grad_cd,'LTC1', 1, 0)) as ltc1,
-               sum(decode(cmtr_grad_cd,'LTC2', 1, 0)) as ltc2,
-               sum(decode(cmtr_grad_cd,'LTC3', 1, 0)) as ltc3,
-               sum(decode(cmtr_grad_cd,'LTC0', 1, 0)) as ltc0,
+        select prcn_dt, sum(ltc1) as ltc1, sum(ltc2) as ltc2, sum(ltc3) as ltc3, sum(ltc0) as ltc0,
                0 as total, 0 as rate_ltc1, 0 as rate_ltc2, 0 as rate_ltc3, 0 as rate_ltc0
-        from tb_ifsc_traf_hs
-        where prcn_dt >= to_char(sysdate-1/24, 'YYYYMMDDHH24MISS')
-        group by prcn_dt, cmtr_grad_cd
+        from (select prcn_dt,
+                     sum(decode(cmtr_grad_cd,'LTC1', 1, 0)) as ltc1,
+                     sum(decode(cmtr_grad_cd,'LTC2', 1, 0)) as ltc2,
+                     sum(decode(cmtr_grad_cd,'LTC3', 1, 0)) as ltc3,
+                     sum(decode(cmtr_grad_cd,'LTC0', 1, 0)) as ltc0
+              from tb_ifsc_traf_hs
+              where prcn_dt >= to_char(sysdate-1/24, 'YYYYMMDDHH24MISS')
+              group by prcn_dt, cmtr_grad_cd
+             )
+        group by prcn_dt
         order by prcn_dt
         ]]>
     </select>
 
     <select id="findAllCmtrGradCountSttsRoad" resultType="com.its.op.dto.its.dashboard.CmtrGradCountSttsDto">
         <![CDATA[
-        select prcn_dt,
-               sum(decode(cmtr_grad_cd,'LTC1', 1, 0)) as ltc1,
-               sum(decode(cmtr_grad_cd,'LTC2', 1, 0)) as ltc2,
-               sum(decode(cmtr_grad_cd,'LTC3', 1, 0)) as ltc3,
-               sum(decode(cmtr_grad_cd,'LTC0', 1, 0)) as ltc0,
+        select prcn_dt, sum(ltc1) as ltc1, sum(ltc2) as ltc2, sum(ltc3) as ltc3, sum(ltc0) as ltc0,
                0 as total, 0 as rate_ltc1, 0 as rate_ltc2, 0 as rate_ltc3, 0 as rate_ltc0
-        from tb_road_traf_hs
-        where prcn_dt >= to_char(sysdate-1/24, 'YYYYMMDDHH24MISS')
-        group by prcn_dt, cmtr_grad_cd
+        from (select prcn_dt,
+                     sum(decode(cmtr_grad_cd,'LTC1', 1, 0)) as ltc1,
+                     sum(decode(cmtr_grad_cd,'LTC2', 1, 0)) as ltc2,
+                     sum(decode(cmtr_grad_cd,'LTC3', 1, 0)) as ltc3,
+                     sum(decode(cmtr_grad_cd,'LTC0', 1, 0)) as ltc0
+              from tb_road_traf_hs
+              where prcn_dt >= to_char(sysdate-1/24, 'YYYYMMDDHH24MISS')
+              group by prcn_dt, cmtr_grad_cd
+             )
+        group by prcn_dt
         order by prcn_dt
         ]]>
     </select>