Login

Language :
TitleJava Spring 세션 남은 시간 표시
Java Spring - Showing session remaining time
WriterJi-Seob LeeWrite DateJun 29 2025Modify DateJul 26 2025View Count211

This explains how to display the remaining time of a login session in Java and Spring.

 

Spring Boot can be implemented in a slightly different way, but
we will explain how to implement it in Spring framework. Use the web.xml file.

 

Apply a filter to backend calls from *.do or /api/*,
set the login session expiration time in the cookie,
and read the cookie value from the front end to display the remaining time.

 

Declare the SessionTimeoutCookieFilter filter class
with @Component(“sessionTimeoutCookieFilterBean”).
 
To apply DI to the filter in Spring, you must use DelegatingFilterProxy.
In web.xml, under filter-class in filter.
DI is used to autowire the service that retrieves the session duration.
 

In this source code, personalInfoService.selectSystemEnv(); is used to retrieve the session duration.

 

package isry.itgcms.sysmgmt.util;

import java.io.IOException;
import java.util.Map;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
//import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import isry.itgcms.sysmgmt.personalinfo.service.PersonalInfoService;

@Component("sessionTimeoutCookieFilterBean")
public class SessionTimeoutCookieFilter implements Filter {

    @SuppressWarnings("unused")
    private FilterConfig config;

    @Autowired
    private PersonalInfoService personalInfoService;

	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
		
		HttpServletResponse httpResponse = (HttpServletResponse) response;
        	//HttpServletRequest httpRequest = (HttpServletRequest) request;
        
        	int sessionTime = 30;
        
        	try {
                	Map map = personalInfoService.selectSystemEnv();
                	sessionTime = Integer.parseInt(map.get("SESIN_TMOUT_MINUTES"));
        	} catch (Exception e) {
                	e.printStackTrace();
        	}
        
        	long sessionDurationTime = System.currentTimeMillis() + sessionTime * 60 * 1000; 
        
        
        	Cookie cookie = new Cookie("sessionDurationTime", "" + sessionDurationTime);
        	//cookie.setSecure(true);
        	cookie.setPath("/");
        	httpResponse.addCookie(cookie);
        
        	chain.doFilter(request, response);
	}

	public void init(FilterConfig config) throws ServletException {
		this.config = config;
	}

	public void destroy() {

	}
}

 

The following is the section for registering filters in the web.xml file.
Set the filter class to org.springframework.web.filter.DelegatingFilterProxy,
and register the filter bean, @Component("sessionTimeoutCookieFilterBean").
 
Apply patterns such as *.do or /api/* to url-pattern.  This is your choice.
The session retention time is reset each time the backend program is called.

 

    <filter>
        <filter-name>sessionTimeoutCookieFilterBean</filter-name>
	<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    	<async-supported>true</async-supported> <!-- Support Async -->
    </filter>
    <filter-mapping>
        <filter-name>sessionTimeoutCookieFilterBean</filter-name>
        <url-pattern>*.do</url-pattern> <!-- Your Choice 1 -->
        <url-pattern>/api/*</url-pattern> <!-- Your Choice 2 -->
    </filter-mapping>

 

Below is the front-end source code.
It reads the session expiration time from the cookie and displays the remaining time.

 

<!DOCTYPE html>
<html>
<head>
<title>Time Left</title>

<script type="text/javascript">

var timeInterval = 1000; // 1-second interval calls
var timer;
var timerArr = new Array();
var timeGap = 0;

async function init() {

    const response = await fetch('/getCurrentTime.do');

    console.log("response", response);

    const systemTime = await response.json();

    console.log("systemTime", systemTime);

    // Browser time
    const localTime = new Date().getTime();

    console.log("localTime", localTime);

    timeGap = Number(systemTime) - localTime;

    console.log("timeGap", timeGap);


    showRemaining();
    
    timer = setInterval(showRemaining, timeInterval); // 1-second interval calls
    
    timerArr.push(timer);
}

function showRemaining() {
    
    var timeRemaining = Number(getCookie("sessionDurationTime")) - new Date().getTime() - Number(timeGap);
    
    //console.log("sessionDurationTime", getCookie("sessionDurationTime"));
    //console.log("unix time", new Date().getTime());
    //console.log("timeRemaining", timeRemaining);
    
    if (timeRemaining < timeInterval) {
        
        for (var i = 0; i < timerArr.length; i++) {
            clearInterval(timerArr[i]);
        }
        
	timerArr = new Array();
        
        setTimeout(function() {
            alert("Session expired.");
        }, 1000);
        
        return;
    }
    
    var timeHour = Math.floor(timeRemaining / 1000 / 60 / 60);
    var timeMin = Math.floor((timeRemaining / 1000 / 60) % 60);
    var timeSec = Math.floor((timeRemaining / 1000) % 60);
    
    const formattedHours = String(timeHour).padStart(2, '0');
    const formattedMinutes = String(timeMin).padStart(2, '0');
    const formattedSeconds = String(timeSec).padStart(2, '0');

    document.getElementById("timeRemaining").innerHTML 
        = formattedHours + ":" + formattedMinutes + ":" + formattedSeconds;
}

function getCookie(psName) {
    var vsCookie = document.cookie + ";";

    var vaItems = vsCookie.split(";");
    var vnItemLen = vaItems.length;
    var item = null;
    var voItemInfo = null;
    for (var i = 0; i < vnItemLen; i++) {
        item = vaItems[i];
        voItemInfo = item.split("=");
        if (psName == voItemInfo[0].trim()) {
            return unescape(voItemInfo[1]);
        }
    }
    return "";
}

</script>

</head>

<body onload="init();">

Time remaining : <span id="timeRemaining"></span>

</body>

</html>

 

const response = await fetch('/getCurrentTime.do');
 
The above code retrieves the current time value from the server
to compensate for the difference
between the local computer's time and the actual time.
 
The source code for .do is shown below.
 
package isry.itgcms.sysmgmt.util;

import java.time.Instant;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class CurrentTime {

	@RequestMapping(value = "/getCurrentTime.do")
	@ResponseBody
	public Long getCurrentTime(HttpServletRequest request, HttpServletResponse response) throws Exception {
        
        	long timestamp = System.currentTimeMillis();
        	System.out.println("current timestamp (milli seconds): " + timestamp);
        

		Instant timestamp1 = Instant.now();
		System.out.println("current timestamp: " + timestamp1);

		// Convert timestamp to milli seconds
		long milliseconds = timestamp1.toEpochMilli();
		System.out.println("current timestamp (milli seconds): " + milliseconds);
		
		return milliseconds;
	}

}

 

In Spring Boot, you can register filters as follows.

 

import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import isry.itgcms.sysmgmt.util.SessionTimeoutCookieFilter;

@Configuration
public class MyFilterConfig {

    @Bean
    public FilterRegistrationBean sessionTimeoutCookieFilter() {
        FilterRegistrationBean registration = new FilterRegistrationBean<>();
        registration.setFilter(new SessionTimeoutCookieFilter());
        registration.addUrlPatterns("*.do");
	registration.addUrlPatterns("/api/*");
        registration.setAsyncSupported(true);
        return registration;
    }
}

 

Async Supported is not a requirement, but may be necessary in some cases.

 

[ Referenced Page ]

  • ChatGPT
  • Google AI

 

Attachment File
CurrentTime.java (1,026 byte)
timeLeft.html (2,553 byte)

Comment

Name               Password 
Content
Check Password.

Please enter your password when registering your comment.