Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | ||||
4 | 5 | 6 | 7 | 8 | 9 | 10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 |
18 | 19 | 20 | 21 | 22 | 23 | 24 |
25 | 26 | 27 | 28 | 29 | 30 | 31 |
Tags
- mysql
- UXUI챌린지
- 국비지원
- 티스토리챌린지
- 백엔드 부트캠프
- KDT
- 환급챌린지
- 디자인교육
- Be
- 객체지향
- Java
- 내일배움카드
- 디자인강의
- 백준
- 국비지원취업
- 디자인챌린지
- Spring
- 오블완
- 부트캠프
- 패스트캠퍼스
- UXUI기초정복
- 백엔드
- 국비지원교육
- UXUIPrimary
- 백엔드개발자
- 내일배움캠프
- 오픈패스
- 오픈챌린지
- OPENPATH
- baekjoon
Archives
- Today
- Total
군만두의 IT 공부 일지
[스터디7] 05. 스프링 웹 스코프 본문
목차
9장. 스프링 웹 스코프
이 장에서 다룰 내용
- 스프링 웹 스코프 사용하기
- 웹 앱에서 간단한 로그인 기능 구현하기
- 웹 앱에서 한 페이지에서 다른 페이지로 리디렉션하기
9.2 스프링 웹 앱에서 세션 스코프 사용
- 세션 스코프 빈: 스프링에서 관리되는 객체. 스프링이 인스턴스를 생성하고 이를 HTTP 세션에 연결하는 역할을 한다.
- 클라이언트가 서버에 요청을 보내면 서버는 세션의 전체 기간 동안 이 요청을 위한 메모리 공간을 예약한다.
- 스프링은 특정 클라이언트에 대해 HTTP 세션이 활성화되어 있는 동안 동일한 클라이언트에서 재사용될 수 있다.
- 세션 스코프 빈 속성에 저장된 데이터는 HTTP 세션 동안 클라이언트의 모든 요청에 사용할 수 있다.
- 이 방식을 통해 사용자가 앱의 웹 페이지를 서핑하는 동안 수행하는 작업 정보의 저장이 가능하다.
세션 스코프 빈과 요청 스코프 빈을 비교하면 다음과 같다.
- 요청 스코프 빈: 스프링은 매 HTTP 요청마다 새로운 인스턴스를 생성한다.
- 세션 스코프 빈: 스프링은 HTTP 세션당 하나의 인스턴스만 생성한다. 세션 스코프 빈에 동일한 클라이언트의 여러 요청 사이에 공유할 데이터를 저장할 수 있다.
세션 스코프 빈을 사용하여 구현할 수 있는 기능은 다음과 같다.
- 로그인: 인증된 사용자가 앱의 여러 부분을 탐색하고 요청 전송하는 동안 그 사용자의 세부 정보를 유지한다.
- 온라인 쇼핑 장바구니: 사용자가 앱의 여러 곳을 방문하여 장바구니에 추가할 제품을 검색한다. 장바구니는 고객이 추가한 모든 제품을 보관한다.
세션 스코프 빈의 핵심 관점
사실 | 결과 | 고려 사항 | 기피 사항 |
|
|
|
|
9.1에서 구현한 애플리케이션을 로그인한 사용자만 액세스할 수 있는 웹 페이지를 표시하도록 변경히려면 다음과 같이 수행해야 한다.
- 로그인한 사용자의 상세 정보를 유지할 세션 범위의 빈을 생성한다.
- 사용자가 로그인한 후에만 액세스할 수 있는 웹 페이지를 만든다.
- 사용자가 먼저 로그인하지 않으면 2.에서 만든 웹 페이지에 액세스할 수 없게 한다.
- 인증에 성공하면 사용자를 로그인에서 메인 페이지로 리디렉션한다.
// 1단계: 로그인 상세 정보를 유지하려고 세션 스코프 빈을 생성한다.
package com.example.services;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.SessionScope;
@Service
@SessionScope
public class LoggedUserManagementService {
private String username;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
}
<!-- 2단계: 로그인했을 때만 액세스할 수 있는 웹 페이지를 만든다. -->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h1>Welcome, <span th:text="${username}"></span></h1>
<a href="/main?logout">Log out</a>
</body>
</html>
// 3단계: 먼저 로그인하지 않고 2단계에서 만든 웹 페이지에 액세스할 수 없는지 확인한다.
package com.example.controllers;
import com.example.services.LoggedUserManagementService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class MainController {
private final LoggedUserManagementService loggedUserManagementService;
public MainController(LoggedUserManagementService loggedUserManagementService) {
this.loggedUserManagementService = loggedUserManagementService;
}
@GetMapping("/main")
public String home(
@RequestParam(required = false) String logout,
Model model
) {
if (logout != null) {
loggedUserManagementService.setUsername(null);
}
String username = loggedUserManagementService.getUsername();
if (username == null) {
return "redirect:/";
}
model.addAttribute("username" , username);
return "main.html";
}
}
// 4단계: 인증을 성공하면 로그인에서 메인 페이지로 리디렉션한다.
package com.example.controllers;
import com.example.model.LoginProcessor;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class LoginController {
private final LoginProcessor loginProcessor;
public LoginController(LoginProcessor loginProcessor) {
this.loginProcessor = loginProcessor;
}
@GetMapping("/")
public String loginGet() {
return "login.html";
}
@PostMapping("/")
public String loginPost(
@RequestParam String username,
@RequestParam String password,
Model model
) {
loginProcessor.setUsername(username);
loginProcessor.setPassword(password);
boolean loggedIn = loginProcessor.login();
if (loggedIn) {
return "redirect:/main";
}
model.addAttribute("message", "Login failed!");
return "login.html";
}
}
9.3 스프링 웹 앱에서 애플리케이션 스코프 사용
- 애플리케이션 스코프(application scope): 싱글톤 작동 방식과 비슷하다. 컨텍스트에 동일한 타입의 인스턴스가 없고, 웹 스코프(애플리케이션 스코프 포함)의 라이프사이클을 논의할 때 항상 HTTP 요청을 참조 기준점으로 사용한다.
- 빈의 속성을 불변으로 만들면 싱글톤 빈을 직접 사용할 수 있다.
- 일반적으로 애플리케이션 빈 대신에 데이터베이스와 같은 영속성(persistence) 계층을 직접 사용하는 편이 좋다.
로그인 시도 횟수를 계산하는 기능을 추가하려면 다음과 같다.
// 1. 로그인 시도 횟수 세기
package com.example.services;
import org.springframework.stereotype.Service;
import org.springframework.web.context.annotation.ApplicationScope;
@Service
@ApplicationScope
public class LoginCountService {
private int count;
public void increment() {
count++;
}
public int getCount() {
return count;
}
}
// 2. 모든 로그인 요청에 대한 로그인 횟수 구현하기
package com.example.model;
import com.example.services.LoggedUserManagementService;
import com.example.services.LoginCountService;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
@Component
@RequestScope
public class LoginProcessor {
private final LoggedUserManagementService loggedUserManagementService;
private final LoginCountService loginCountService;
private String username;
private String password;
public LoginProcessor(LoggedUserManagementService loggedUserManagementService, LoginCountService loginCountService) {
this.loggedUserManagementService = loggedUserManagementService;
this.loginCountService = loginCountService;
}
public boolean login() {
loginCountService.increment();
String username = this.getUsername();
String password = this.getPassword();
boolean loginResult = false;
if ("natalie".equals(username) && "password".equals(password)) {
loginResult = true;
loggedUserManagementService.setUsername(username);
}
return loginResult;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
// 3. 컨트롤러의 로그인 횟수 값을 메인 페이지에 표시하려고 전송하기
package com.example.controllers;
import com.example.services.LoggedUserManagementService;
import com.example.services.LoginCountService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
@Controller
public class MainController {
private final LoggedUserManagementService loggedUserManagementService;
private final LoginCountService loginCountService;
public MainController(LoggedUserManagementService loggedUserManagementService, LoginCountService loginCountService) {
this.loggedUserManagementService = loggedUserManagementService;
this.loginCountService = loginCountService;
}
@GetMapping("/main")
public String home(
@RequestParam(required = false) String logout,
Model model
) {
if (logout != null) {
loggedUserManagementService.setUsername(null);
}
String username = loggedUserManagementService.getUsername();
int count = loginCountService.getCount();
if (username == null) {
return "redirect:/";
}
model.addAttribute("username" , username);
model.addAttribute("loginCount", count);
return "main.html";
}
}
<!-- 4. 메인 페이지에 로그인 횟수 표시하기 -->
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
<meta charset="UTF-8">
<title>Login</title>
</head>
<body>
<h1>Welcome, <span th:text="${username}"></span>!</h1>
<h2>Your login number is <span th:text="${loginCount}"></span></h2>
<a href="/main?logout">Log out</a>
</body>
</html>
이 글은 『스프링 교과서』 책을 학습한 내용을 정리한 것입니다.
'프로그래밍 > Java' 카테고리의 다른 글
[스터디7] 04. 스프링 부트와 스프링 MVC 이해 (0) | 2025.05.06 |
---|---|
[스터디7] 03. 스프링 컨텍스트: 빈의 스코프 및 수명 주기 (0) | 2025.04.29 |
[스터디7] 02. 스프링 컨텍스트: 추상화 (0) | 2025.04.22 |
[스터디7] 01. 스프링 컨텍스트: 빈 정의 (0) | 2025.04.11 |
[스터디4] 09. 자바 21에서 강화된 언어 및 라이브러리 (0) | 2025.04.02 |
Comments