online user - woowa-turkey/miniprojects-2019 GitHub Wiki
์ฒ์ ์๊ฐ
DB์ ๋ก๊ทธ์ธ ์๊ฐ๊ณผ ๋ก๊ทธ์์ ์๊ฐ์ ์ ์ฅ
๋ก๊ทธ์ธ ์๊ฐ์ด ๋ก๊ทธ์์ ์๊ฐ ๋น ๋ฅด๋ฉด โ ๋ก๊ทธ์ธ
๋ก๊ทธ์ธ ์๊ฐ์ด ๋ก๊ทธ์์ ์๊ฐ ๋ฆ์ผ๋ฉด โ ๋ก๊ทธ์์
์ด๊ธฐ User ์์ฑ์์๋ ์๊ฐ์ ๊ฐ๊ฒ ํด๋๊ณ ์๊ฐ์ด ๊ฐ์ผ๋ฉด ๋ก๊ทธ์์์ผ๋ก ์ฒ๋ฆฌ
public boolean isLogin() {
return loginAt.isAfter(logoutAt);
}
๋ฌธ์ ์ 1. ๋ก๊ทธ์์์ ์ํ๊ณ ๋ธ๋ผ์ฐ์ ๋ฅผ ์ข ๋ฃํ๊ฑฐ๋ ๋ค๋ฅธ ํ์ด์ง๋ก ๋์ด๊ฐ๋ ๊ฒฝ์ฐ
๋ฐฉ๋ฒ 1. js์ ์๋ unload ์ด๋ฒคํธ ํ์ฉํด์ "๋ค๋ฅธ ํ์ด์ง๋ก ๋์ด๊ฐ๋ ๋ก๊ทธ์์ํ์๊ฒ ์ต๋๊น?"๋ผ๋ ๋ฉ์ธ์ง๋ฅผ ๋ณด์ฌ์ฃผ๋ฉด ๋๊ฒ ๋ค.
window,document,resources๊ฐ unload๋ ๋ ๋ฐ์ํ๋ ์ด๋ฒคํธ ์์ : beforeunload โ pagehide โ unload
-
beforeunload
์ด ์ด๋ฒคํธ๊ฐ ๋ฐ์ํ ๋น์์๋ ํ๋ฉด์ ์ฌ์ ํ ํ์๋๊ณ ์ทจ์ํ ์ ์๋ค.
- ์ฌ์ฉ๋ฐฉ๋ฒ
// beforeunload event ์ฌ์ฉ๋ฐฉ๋ฒ 1. window.addEventListener('beforeunload', function(event) { // ๊ธฐ๋ณธ์ ์๋ ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ํ์ธ์ฐฝ์ ๋์ด๋ค. event.preventDefault(); // Chrome ํฌ๋กฌ์ returneValue์ ๊ฐ์ ๋ฃ์ด์ค์ผ ํ๋ค. ์๋ฏธ๋ ์๋ค. event.returnValue = ''; // ์ผ๋ถ ๋ธ๋ผ์ฐ์ ๋ string returnํด์ผํ๋ค. }); 2. window.onbeforeunload = function(event) { // ๊ธฐ๋ณธ์ ์๋ ๋ฉ์๋๋ฅผ ์ด์ฉํด์ ํ์ธ์ฐฝ์ ๋์ด๋ค. event.preventDefault(); // Chrome ํฌ๋กฌ์ returneValue์ ๊ฐ์ ๋ฃ์ด์ค์ผ ํ๋ค. ์๋ฏธ๋ ์๋ค. event.returnValue = ''; // ์ผ๋ถ ๋ธ๋ผ์ฐ์ ๋ string returnํด์ผํ๋ค. };
๋จ์
- IE์ ์ธํ๊ณ ๋ ๋ฉ์์ง ์ปค์คํ ์ด ๋ถ๊ฐ๋ฅ
- ๋ก๊ทธ์์์ด ์ ์ฅ์ ์ผ๋ก ๋์๋์ง ์ ์ ์๋ค.
- ์๋ก๊ณ ์นจํ๊ฑฐ๋ ๋ค๋ฅธ ํ์ด์ง๋ก ๋์ด๊ฐ ๋๋ ๋ฌด์กฐ๊ฑด ์คํ๋๋ค.
-
pagehide
์ทจ์๊ฐ ๋ถ๊ฐ๋ฅํ๋ค.
์ฌ์ฉ์์๊ฒ ๋ญ๊ฐ ํ์๋ฅผ ํด์ค ์ ์๋ค.(alert, confirm ๋ฑ ๋ถ๊ฐ๋ฅ)
firefox์ ์ธํ๊ณ ๋ธ๋ผ์ฐ์ ํธํ์ฑ์ด ์๋ฒฝํ์ง ์๋ค.
(ํฌ๋กฌ์์๋ ๋ค๋ก๊ฐ๊ธฐ ์ํ์ js๋ฅผ ์ฌ์คํํ๊ณ firefox๋ BFCache๋ฅผ ์ฌ์ฉํด์ ์ ์ฅํด ๋์ ์ด์ ํ์ด์ง๋ฅผ ๋ฐ๋ก ๋ก๋ํ๋๋ฐ ๋ค๋ก๊ฐ๊ธฐ ์ํ์์๋ ๋์ํ๋ ์ฝ๋๋ฅผ ๋ณดํต pageshow, pagehide์ ๋ฃ๋๋ค๊ณ ํ๋ค.)
- ์ฌ์ฉ๋ฐฉ๋ฒ
window.addEventListener('pagehide', function(event) { if (event.persisted) { "The page was cached by the browser" } else { "The page was NOT cached by the browser" } });
-
unload
pagehide์ ๋น์ทํ๋ค.
์ทจ์๊ฐ ๋ถ๊ฐ๋ฅํ๋ค.
์ฌ์ฉ์์๊ฒ ๋ญ๊ฐ ํ์๋ฅผ ํด์ค ์ ์๋ค.(alert, confirm ๋ฑ ๋ถ๊ฐ๋ฅ)
๋ชจ๋ ๋ธ๋ผ์ฐ์ ์์ ์ ํธํ๋๋ค.
- ์ฌ์ฉ๋ฐฉ๋ฒ
window.addEventListener('unload', function(event) { ... });
์ ์ด๋ฒคํธ๋ค์ ๋จ์
- ์ฃผ์๊ฐ ๋ฐ๋๋ ๊ฒฝ์ฐ์ ๋ฌด์กฐ๊ฑด ๋ฐ์ํ๋ค. ์ด๋ค ์ฃผ์๋ก ์ด๋๋ ๊ฒ์ธ์ง ์ ์ ์์ผ๋ฉด url์ ํ์ฑํด์ ์ด๋ป๊ฒ๋ ํ ์ ์์์ง ๋ชจ๋ฅด์ง๋ง ์ด๋ ๋ ์ฃผ์๋ฅผ ์ ์ ์๋ ๋ฐฉ๋ฒ์ ์๋ ๊ฒ ๊ฐ๋ค.
- ์๋ก๊ณ ์นจ ํ ๋๋ ๋ฐ์ํ๋ค.
- ์ฌ์ฉ์์๊ฒ ์ํ๋ ๋ฉ์์ง๋ฅผ ํ์ํด ์ค ์ ์๋ค.
๋ฐฉ๋ฒ 2. session์ด ์ข ๋ฃ๋๋ฉด ๋ก๊ทธ์์ ์๊ฐ์ ๊ฐฑ์ ํ์.
HttpSessionListener๋ฅผ ์ฌ์ฉํด์ sessionDestroyed๋ ๋ logoutAt ๊ฐฑ์
-
HttpSessionListener ์ฌ์ฉ๋ฒ
- ๋ฆฌ์ค๋ ํด๋์ค์
@WebListener
๋ถ์ธ๋ค.
@WebListener public class CustomSessionListener implements HttpSessionListener { private static final Logger log = LoggerFactory.getLogger(CustomSessionListener.class); @Override public void sessionCreated(HttpSessionEvent se) { log.info("์ธ์ ์ด ์ฐ๊ฒฐ๋์์ต๋๋ค. session ID : {}", se.getSession().getId()); } @Override public void sessionDestroyed(HttpSessionEvent se) { log.info("์ธ์ ์ด ๋ง๋ฃ๋์์ต๋๋ค. session ID : {}", se.getSession().getId()); } }
- Application์
@ServletComponentScan
์ ์ฉ
@ServletComponentScan @SpringBootApplication public class TurkeyApplication {
-
Trigger
request.getSession() โ sessionCreated
session.invalidate() โ sessionDestroyed
๋ฌธ์ ์ : ๋ธ๋ผ์ฐ์ ๊ฐ ์ข ๋ฃ๋๊ฑฐ๋ ๋ค๋ฅธ ์ฌ์ดํธ๋ก ์ฎ๊ธด๋ค๊ณ ํด์ ์ธ์ ์ด ๋ง๋ฃ๋์ง ์๋๋ค.
- ๋ฆฌ์ค๋ ํด๋์ค์
๋ฐฉ๋ฒ 3. timeout์ ๋์์ ๋ ๋ก๊ทธ์์ ์๊ฐ์ ๊ฐฑ์ ํ๋ ๋ฐฉ๋ฒ์ ์ฌ์ฉํ์ (ํด๊ฒฐ ๋ฐฉ๋ฒ)
2๋ฒ ๋ฐฉ๋ฒ๊ณผ ์ฝ๋๋ ๋์ผ
session timeout โ sessionDestroyed ํ์ฉ
-
timeout ์ค์ ๋ฐฉ๋ฒ
- global session timeout
๊ธฐ๋ณธ 1800์ด
60์ด ๋จ์ ๋ด๋ฆผ์ผ๋ก ์ค์ ๋๋ค.(179 โ 120)
60์ด๋ฏธ๋ง ์ค์ ๋ถ๊ฐ๋ฅ
30m โ 30๋ถ
# application.yml -> global session timeout server: servlet: session: timeout: 60
- current session timeout
HttpSession session = request.getSession(); session.setMaxInactiveInterval(60);
๋ฌธ์ ์ 2. ๋ก๊ทธ์ธ ์ค์ธ๋ฐ ๋ค์ ๋ก๊ทธ์ธํ๋ ๊ฒฝ์ฐ ์ด์ ๋ก๊ทธ์ธ์ด timeout๋๋ฉด์ ๋๋ฒ์งธ ๋ก๊ทธ์ธํ ์ ์ ๊ฐ ๋ก๊ทธ์ธ ์ํ์ธ๋ฐ๋ ๋ก๊ทธ์์ ๋ ์ ์๋ค.
๋ฌธ์ ์ํฉ : login1 โ ๋ธ๋ผ์ฐ์ ๊ทธ๋ฅ ์ข ๋ฃ โ login2 โ login1 session timeout
ํด๊ฒฐ๋ฐฉ๋ฒ
login2์์ ์ ์ ๊ฐ login์ํ์ด๋ฉด logoutAt์ ๊ฐฑ์ ํ๊ณ loginํ๋ค.
login1 session timeout์ผ๋ logout ์ํ์ด๋ฉด logoutAt์ ๊ฐฑ์ ํ์ง ์๋๋ค.(logoutํ ๋ logout ์ํ์ด๋ฉด logoutAt์ ๊ฐฑ์ ํ์ง ์๋๋ค.)
login ์๊ฐ์ด 30 ๋ถ ์์ชฝ์ด๋ฉด session timeout์ผ๋ก๋ logoutAt์ ๊ฐฑ์ ํ์ง ์๋๋ค.
// LoginService
public UserSession login(final LoginRequest loginRequest) {
try {
User user = userService.findByEmail(loginRequest.getEmail());
user.matchPassword(loginRequest.getPassword());
checkLoginAndUpdateLogoutAt(user);
user.updateLoginAt(LocalDateTime.now());
return UserSession.from(user);
} catch (Exception e) {
throw new LoginFailException(e.getMessage());
}
}
public void logout(final Long userId) {
User user = userService.findById(userId);
checkLoginAndUpdateLogoutAt(user);
}
private void checkLoginAndUpdateLogoutAt(User user) {
if (user.isLogin()) {
user.updateLogoutAt(LocalDateTime.now());
}
}
๋ฌธ์ ์ 3. ์๋ก๊ณ ์นจ ์ํด๋ ์น๊ตฌ๊ฐ ์ ์ ์ข ๋ฃํ๋ฉด ๋ก๊ทธ ์์์ผ๋ก ํ์ ํ๋ ค๋ฉด?
websocket์ ํ์ฉํด์ ๋ก๊ทธ์ธํ๊ฑฐ๋ ๋ก๊ทธ์์ ํ ๋ ์น๊ตฌ๋ค์๊ฒ ๋ฉ์ธ์ง๋ฅผ ๋ณด๋ด์ฃผ๋ฉด ๋์ง์์๊น?