💻 JSP 웹 프로그래밍
- JSP를 처음 공부하는 과정에서 핵심 키워드들 메모장
- 🧩 EASY : 키워드의 정의나 문장을 이해하기 쉽게 요약
📚 JSP 웹 프로그래밍 기초 공부 목록
1️⃣ CHAPTER 01 : 웹 프로그래밍 기초
2️⃣ CHAPTER 02 : 필수 습득
3️⃣ CHAPTER 09 : 클라이언트와의 대화 1 - 쿠키
4️⃣ CHAPTER 10 : 클라이언트와의 대화 2 - 세션
5️⃣ CHAPTER 14 : 데이터베이스 프로그래밍 기초
6️⃣ CHAPTER 17 : 서블릿 기초
7️⃣ CHAPTER 18 : MVC 패턴 구현
8️⃣ CHAPTER 19 : 필터
❗️ 멘토링 수업 과제
1. 클라이언트가 브라우저 주소창에 URL을 입력하고 엔터를 누른 순간부터 화면이 보이기까지, 어떤 일이 일어나는지 본인이 아는 만큼 설명해주세요.
DNS 조회 → TCP 연결 → TLS(HTTPS면) → HTTP 요청 → 서버 처리 → HTTP 응답 → 브라우저 렌더링 → 화면 표시
🧩 EASY
- 예를 들어 클라이언트가 www.naver.com
이라는 URL을 입력하면, 인터넷에서는 IP 주소를 기반으로 통신하기 때문에 DNS 서버를 통해 도메인을 해당 서버의 IP 주소로 조회합니다. - IP 주소를 얻은 후, 클라이언트는 서버와 통신하기 위해 TCP 연결을 시도합니다. TCP는 인터넷에서 데이터를 신뢰성 있게 전달하기 위한 전송 계층 프로토콜이 며, HTTP는 일반적으로 TCP 위에서 동작합니다.
TCP는 연결 지향 프로토콜이기 때문에 데이터를 보내기 전에 먼저 연결을 수립해야 합니다.
이때 3-Way Handshake 사용하고 이 과정을 통해 양쪽이 통신 가능 여부와 초기 시퀀스 번호를 동기화 하고 연결을 확립한 뒤, 안전한 데이터 통신을 할 수 있습니다. - 이때 URL이 TLS가 적용된 HTTPS인 경우라면 TLS 핸드세이크가 시작 됩니다.
TLS는 네트워크 상에서 데이터를 안전하게 주고 받기 위한 암호화 프로토콜 입니다.
TLS 핸드세이크 시 서버 인증, 암호화 방식 합의, 세션키 생성이 이루어집니다.
이후 생성된 대칭 세션키로 모든 데이터가 암호화 되어 안전하게 통신됩니다. - 이러한 준비 작업이 다 끝난뒤 브라우저가 서버에 HTTP 요청을 보냅니다.
- 서버는 받은 요청을 WAS로 전달 후 비즈니스 로직을 처리한 뒤 html을 생성하고 응답을 보냅니다.
- 브라우저는 전송받은 html을 화면에 출력하기 위해 렌더링을 하게 되는데
렌더링 과정은 HTML을 파싱하여 DOM을 생성하고, CSS를 파싱하여 CSSOM을 생성합니다.
이후 DOM과 CSSOM을 결합하여 Render Tree를 만들고, Layout 단계에서 각 요소의 위치와 크기를 계산한 뒤, Paint를 통해 픽셀 단위로 그립니다. 마지막으로 Paint로 만들어진 여러 레이어를 합치는 Composite 과정을 통해 화면에 출력됩니다.
- 예를 들어 클라이언트가 www.naver.com
- 1️⃣ DNS 조회
- www.naver.com 같은 URL을 입력 하면 컴퓨터는 IP 주소로 통신하기 때문에 URL 주소를 DNS 서버를 통해 IP 주소로 변환 해야한다.
2️⃣ TCP(Transmission Control Protocol) 연결
TCP 란 인터넷에서 데이터를 신뢰성 있게 보내기 위한 통신 규칙으로 데이터를 정확하고, 순서대로, 빠짐없이 보내주는 연결 지향 프로토콜 이다.
TCP 의 목적
- 패킷이 중간에 사라질 수 있음 - 순서가 바뀔 수 있음 - 중복으로 올 수 있음TCP 특징
1. 연결 지향 - 3-way handshake - Client Server | ---- SYN -------> | synchronize(동기화하다) | <--- SYN+ACK ---- | Acknowledgment(수신) | ---- ACK -------> | - 양쪽의 연결 준비 상태와 초기 시퀀스 번호를 동기화한다. 2. 신뢰성 보장 - 데이터 누락 시 재전송 - 도착 확인(ACK) 받음 - 오류 검사 3. 순서 보장 4. 흐름 제어/ 혼잡 제어
3️⃣ TLS(Transport Layer Security)
TLS 란 온라인 네트워크에서 데이터를 안전하게 주고 받기 위한 암호화 보안 프로토콜
HTTPS = HTTP + TLS 로 HTTP는 평문이기 때문에 이를 암호화 해준다.
TLS 특징
암호화
- 데이터를 암호화해서 중간에서 못 읽게 한다
무결성
- 중간에서 데이터를 변조하면 알 수 있다
인증
- 진짜 서버인지 확인
4️⃣ HTTP 요청
브라우저가 서버로 요청을 보냄
ex) GET / HTTP/1.1 Host: www.naver.com User-Agent: Chrome Cookie: sessionId=1234 - 요청 메서드(GET, POST등) - 헤더 - 쿠키
5️⃣ 서버 내부 처리
- 웹 서버가 요청 받음
- WAS 로 전달
- 컨트롤러 실행
- DB 조회
- 비즈니스 로직 처리
- HTML 생성
6️⃣ HTTP 응답
서버가 응답을 보냄
ex) HTTP/1.1 200 OK Content-Type: text/html <html> ... </html>
- 7️⃣ 브라우저 렌더링
- 8️⃣ 화면 출력
2. HTTP 특징에 대해서 설명해주세요.
클라이언트 - 서버 구조
- 항상 요청 -> 응답 구조
⭐️ 무상태성 (Stateless) ⭐️
HTTP 는 상태를 기억하지 않는다. (서버는 클라이언트 상태를 저장하지 않는다.)
로그인 요청 -> 다음 요청 시 서버는 "이 사람이 방금 로그인 한 사람" 인지 모름
그래서 쿠키나 세션, 토큰이 필요하다.
무상태성의 장,단점
장점)
서버 확장성이 좋다
- 서버가 클라이언트 상태를 저장하지 않기 때문에 서버를 여러대로 늘려도 문제가 없음
- 요청이 아무 서버로 가도 됨
- 대규모 서비스에 유리
서버 구조가 단순하다
- 세션 저장, 사용자 상태 관리 필요 없음
장애 대응이 쉽다
- 특정 서버가 죽어도 다른 서버가 그대로 처리 가능
단점)
매 요청마다 인증 정보를 보내야 함
-> 트래픽 증가로그인 유지 구현이 어려움
- 그래서 쿠키나 세션,토큰이 필요함
비연결성
- 요청 한개가 끝나면 응답을 끊는다.
- 요청 -> 응답 -> 연결종료
- 서버 자원 절약을 위해
확장 가능
HTTP 는 헤더 기반 구조라서 새로운 기능을 추가 가능하다
HTTP는 본문(body) 형식이 뭐든 상관 없이, 헤더로 ‘이 요청/응답을 어떻게 취급할지’를 계속 덧붙일 수 있다.
Authorization: 인증/인가 기능을 "확장"
Content-Type: 바디 포맷을 "확장"
Cache-Control: 캐싱 정책을 "확장"
- 메시지 기반 프로토콜
- HTTP는 요청과 응답을 완결된 메시지 단위로 주고받는 메시지 기반 프로토콜이다.
- 이로 인해 요청의 독립성이 보장되며, 확장성과 디버깅이 용이하고, 프록시·캐시 같은 중간 계층이 개입하기 쉽다는 장점이 있다.
3. HTTP는 왜 "stateless(무상태)" 프로토콜이라고 하나요
- HTTP 는 서버가 클라이언트의 상태를 기억하지 않기 때문에 무상태 프로토콜이라고 생각합니다.
- 예를 들어 1.로그인 요청 -> 2./mypage 요청 시 서버는 이 사람이 방금 로그인 한 사람인지 기억하지 않습니다.
- 각 요청은 완전히 독립적인 메시지 입니다.
3. stateless라서 생기는 문제는 무엇이고, 이를 어떻게 해결하나요?
문제점
- 로그인 유지가 안됨
- 사용자별 상태 관리가 어려움
- 매 요청마다 인증 정보를 포함 해야한다.
해결 방법
- 쿠키, 세션, JWT와 같은 메커니즘 사용
4. GET 요청과 POST 요청의 차이를 설명해주세요. "GET은 조회, POST는 등록"이라는 설명 외에 기술적인 차이도 이야기해주세요.
- 🧩 EASY
- GET과 POST의 가장 큰 차이는 데이터 전송 위치와 멱등성입니다.
GET은 URL 쿼리문자열을 통해 데이터를 전송하며, 여러 번 호출해도 동일한 결과를 보장하는 멱등성을 가집니다. 또한 캐시가 가능하고 브라우저 기록에 남습니다.
반면 POST는 HTTP Body에 데이터를 담아 전송하며, 요청마다 서버 상태가 변경될 수 있어 멱등성이 보장되지 않습니다. 따라서 자동 재시도나 캐시 측면에서도 차이가 있습니다
- GET과 POST의 가장 큰 차이는 데이터 전송 위치와 멱등성입니다.
4.1) 본질적인 차이
| 구분 | GET | POST |
|---|---|---|
| 목적 | 리소스 조회 | 리소스 생성/처리 |
| 데이터 위치 | URL 쿼리스트링 | HTTP Body |
| 캐시 | 가능 | 기본적으로 불가 |
| 브라우저 기록 | 남음 | 안 남음 |
| 멱등성 | O | X |
| 안전성 | Safe | Unsafe |
| 길이 제한 | URL 길이 제한 있음 | 거의 없음 |
4.2) 기술적인 차이
1. 데이터 전송 위치 차이
GET(조회)
- GET /search?q=java&page=1 HTTP/1.1
- 데이터가 URL에 붙는다.
- 쿼리 문자열 사용
- 서버는 URL을 보고 처리한다.
POST(생성)
POST /members HTTP/1.1
Content-Type: application/json{
"name": "kim",
"age": 30
}데이터는 body에 담긴다.
JSON, form-data, XML 등 가능
2. 멱등성(여러번 요청해도 결과가 같은가?)
- GET 은 여러번 해도 결과가 동일(멱등성O)
- POST 는 여러번 보내면 데이터가 여러개 생성됨(멱등성X)
- 그래서 재요청, 자동 재시동 상황에서 GET은 안전하지만 POST는 위험하다.
3. 안전성
4. 캐시 가능 여부
GET은 캐시 가능
- 뒤로가기
- 동일 요청 반복
POST는 서버 상태를 바꾸는 요청일 가능성이 높아 기본적으로 캐시 안함
5. 길이 제한
- GET은 URL의 길이 제한이 있지만, POST는 body에 담기기 때문에 사실상 길이의 제한이 없습니다.
5. HTTP 상태 코드는 무엇인가요?
- 🧩 EASY
- HTTP 상태 코드는 클라이언트 요청을 성공했는지 실패했는지 서버에서 알려주는 3자리 숫자로 표현한 것입니다.
이를 통해 클라이언트는 요청 결과에 따라 적절한 후속 처리를 할 수 있습니다.
- HTTP 상태 코드는 클라이언트 요청을 성공했는지 실패했는지 서버에서 알려주는 3자리 숫자로 표현한 것입니다.
5.1) 상태 코드 구조 (5가지 분류)
| 범위 | 의미 |
|---|---|
| 1xx | 정보 응답 |
| 2xx | 성공 응답 |
| 3xx | 리다이렉트 메시지 |
| 4xx | 클라이언트 오류 응답 |
| 5xx | 서버 오류 응답 |
5.2) 자주 쓰는 상태 코드들
1XX : 요청이 수신되어 처리중
상태 코드 상태 메세지 설명 100 Continue 요청의 일부가 정상적으로 수신되었으며, 클라이언트는 나머지 요청을 계속 전송해도 됨 101 Switching Protocols 서버가 클라이언트의 요청에 따라 프로토콜을 변경 중임 (예: HTTP → WebSocket) 102 Processing 서버가 요청을 처리 중이지만, 아직 최종 응답을 보낼 수 없는 상태임 103 Early Hints 본 응답 전에 필요한 리소스 정보를 미리 제공하여 브라우저가 사전 로드(preload)하도록 도움
2XX : 요청이 정상적으로 처리 되었다는 의미를 가진다.
상태 코드 상태 메세지 설명 200 OK 요청 성공 201 Created 리소스 생성 성공 (예: 회원가입, 게시글 작성 등) 204 No Content 요청은 성공했지만 응답 본문이 없음 206 Partial Content 콘텐츠의 일부만 제공. 클라이언트가 Range를 지정해 다운로드 일부만 요청한 경우 사용
3XX : 리다이렉션을 의미하며, 이는 요청을 완료하려면 추가적인 작업이 필요함을 의미한다.
클라이언트가 관심 있어 하는 리소스에 대해 다른 위치를 사용하라고 말해주거나 그 리소스의 내용 대신 다른 대안 응답을 제공한다.리다이렉션(Redirection)은 클라이언트가 요청한 URL에 대해 다른 URL을 다시(re) 지시(direct)하여 다른 주소로 이동할 수 있게 하는 기술이다. HTTP 에 사용되는 리다이렉션은 크게 3가지 종류로 나눌 수 있다.
영구 리다이렉션(Permanent) : 특정 리소스의 URL 이 영구적으로 이동
일시 리다이렉션(Temporary) : 특정 리소스의 URL 이 일시적으로 이동
특수 리다이렉션(Special) : 캐시를 활용할 것인지에 대한 여부
| 상태 코드 | 상태 메세지 | 설명 |
|---|---|---|
| 301 | Moved Permanently | 요청한 리소스가 새 위치로 영구적으로 이동함. 브라우저는 자동으로 새 URL로 이동하며, 이후 요청도 새 주소를 사용함 |
| 302 | Found | 요청한 리소스가 임시로 다른 위치에 존재함. 브라우저는 새 URL로 이동하지만, 이후 요청 시 원래 주소를 계속 사용함 |
- 4XX : 클라이언트 오류를 의미하며, 잘못된 문법 등의 오류로 인해 서버가 요청을 수행할 수 없고 그 원인이 클라이언트에게 있음을 뜻한다.
잘못 구성된 요청 메세지 같은 것이 있을 수 있으며, 존재하지 않은 URL 요청도 있을 수 있다.
| 상태 코드 | 상태 메세지 | 설명 |
|---|---|---|
| 400 | Bad Request | 클라이언트가 잘못된 요청을 보냄. 요청 구문, 파라미터, 메시지 형식 등의 문법 오류 |
| 401 | Unauthorized | 인증(authentication)이 되지 않아 요청을 수행할 수 없음 (실제 의미는 Unauthenticated에 가까움) |
| 403 | Forbidden | 인증은 되었지만 권한(authorization)이 없어 접근할 수 없음 (예: 로그인은 했지만 권한 부족) |
| 404 | Not Found | 요청한 리소스가 서버에 존재하지 않음 |
5XX : 5xx 번대의 상태 코드들은 서버 오류를 의미하며, 400 번대와 동일하게 오류로 인한 요청 처리 실패를 의미하지만 원인이 서버에게 있음을 뜻한다.
4XX 상태코드와 5XX 상태코드 모두 오류를 반환하는 응답 코드이지만, 4XX는 클라이언트의 요청에 문제가 있는 것이기에 요청 메세지를 검토하여 수정한 뒤 재전송하면 해결이 가능하지만, 5XX 는 서버에 문제가 있는 것이기 때문에 서버 자체의 상태를 보아야 하는 차이가 있다.
| 상태 코드 | 상태 메세지 | 설명 |
|---|---|---|
| 500 | Internal Server Error | 서버 내부 문제 발생. 트래픽 폭주, 백엔드 스크립트 오류 등 다양한 원인이 있으며, 정확한 원인을 특정할 수 없을 때 반환 |
| 503 | Service Unavailable | 서버가 과부하 상태이거나 점검 중이라 현재 요청을 처리할 수 없음 |
6. 쿠키란 무엇이고, 서버와 클라이언트 사이에서 어떻게 주고받나요? HTTP 헤더 레벨에서 설명해주세요.
🧩 EASY
- 쿠키는 서버가 클라이언트에 저장하도록 지시하는 작은 데이터이며, HTTP의 무상태 특성을 보완하기 위해 사용됩니다.
서버는 응답 헤더의 Set-Cookie를 통해 쿠키를 생성하고, 이후 클라이언트는 요청 시 Cookie 헤더에 해당 값을 자동으로 포함시켜 서버에 전송합니다.
이를 통해 서버는 사용자를 식별하거나 세션을 유지할 수 있습니다.
- 쿠키는 서버가 클라이언트에 저장하도록 지시하는 작은 데이터이며, HTTP의 무상태 특성을 보완하기 위해 사용됩니다.
6.1 쿠키란?
- 쿠키는 서버가 클라이언트(브라우저)에 저장해두는 작은 데이터 조각
- HTTP의 특징인 무상태을 해결하기 위해 쿠키를 사용
6.2 서버 -> 클라이언트 (쿠키 생성)
HTTP/1.1 200 OK
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure
Content-Type: text/html- 서버는 응답 헤더에 Set-cookie 를 넣는다.
- sessionId=abc123 → 키=값
- Path=/ → 모든 경로에서 전송
- HttpOnly → JS 접근 불가 (XSS 방지)
- Secure → HTTPS에서만 전송
- 브라우저가 이것을 저장
6.3 클라이언트 -> 서버 (쿠키 요청)
GET /mypage HTTP/1.1
Host: example.com
Cookie: sessionId=abc123이후 같은 도메인에 요청하면 브라우저가 자동으로 Cookie 헤더를 붙여서 보냄.
서버는 이 값을 보고
- 로그인 상태 판단
- 사용자 식별
- 세션 조회
7. 쿠키는 왜 사용하는걸까요?
- HTTP는 무상태 프로토콜이기 때문에 요청 간 상태를 유지할 수 없습니다.
이를 보완하기 위해 서버는 쿠키를 통해 클라이언트에 식별 정보를 저장하고, 이후 요청 시 해당 쿠키를 함께 전송하도록 합니다.
이를 통해 로그인 유지, 사용자 식별, 장바구니 기능 등을 구현할 수 있습니다.
8. 쿠키의 속성에 대해 아는게 있는가?
8.1) 쿠키의 기본 구조
서버 응답
Set-Cookie: sessionId=abc123; Path=/; HttpOnly; Secure; Max-Age=3600; SameSite=Lax구조
Set-Cookie: 이름=값; 속성1; 속성2; 속성3...
8.2) 쿠키 주요 속성들
Path
Set-Cookie: sessionId=abc123; Path=/admin- 해당 경로에서만 쿠키 전송
- /admin 이하 경로에서만 서버로 전송
- 경로 범위 제한 가능
Domain
Set-Cookie: sessionId=abc123; Domain=example.com- 어떤 도메인에서 전송할지 지정
- example.com
- .example.com → 서브도메인 포함
Max - Age
Set-Cookie: sessionId=abc123; Max-Age=3600- 초 단위 유효 시간
- 3600초 = 1시간
- 시간이 지나면 자동 삭제
Expires
Set-Cookie: sessionId=abc123; Expires=Wed, 21 Jun 2026 10:00:00 GMT- 만료 날짜 지정
- Max-Age가 있으면 Expires보다 우선
Secure
Set-Cookie: sessionId=abc123; Secure- HTTPS 에서만 전송
- HTTP 에선 전송 안함
- 중간자 공격 방지
HttpOnly
Set-Cookie: sessionId=abc123; HttpOnly- 자바스크립트에서 접근 불가
- XSS 공격 방지용
SameSite (요즘 매우 중요)
Set-Cookie: sessionId=abc123; SameSite=Strict- 다른 사이트에서 요청할 때 쿠키 전송 여부 결정
값 의미 Strict 같은 사이트에서만 전송 Lax 일부 크로스 요청 허용 None 모두 허용 (Secure 필수)
- 다른 사이트에서 요청할 때 쿠키 전송 여부 결정
9. 쿠키만으로 로그인 상태를 유지하면 어떤 보안 문제가 생길 수 있나요?
- 🧩 EASY
- 쿠키만으로 로그인 상태를 유지하면 쿠키에 로그인 증표를 저장하는 방식일텐데, 이때 생기는 보안 문제들은 쿠키 탈취 시 계정 탈취가 가능하고, 변조 및 CSRF 공격에 취약해질 수 있습니다.
9.1) 발생 가능한 주요 보안 문제들
- 세션 하이재킹
- 공격자가 중간에 쿠키(sessionId)를 탈취해서
사용자인 척 서버에 요청하는 것. - 해결 방법 => 짧은 유효 시간
- 공격자가 중간에 쿠키(sessionId)를 탈취해서
- 세션 하이재킹
- XSS 공격
- 공격자가 취약한 웹사이트에 악성 스크립트를 삽입하여, 해당 페이지를 방문하는 사용자의 브라우저에서 스크립트를 실행시키는 공격입니다.
- 해결 방법 => HttpOnly
- XSS 공격
- 네트워크 스니핑 (HTTPS 미사용)
- HTTP 통신이면 쿠키가 평문으로 전송됨, 공공 와이파이에서 가로채기 가능
- 해결 방법 => Secure
- 네트워크 스니핑 (HTTPS 미사용)
- CSRF (Cross-Site Request Forgery)
- 예를 들어 은행 사이트에 로그인 돼있을때 다른 악성 사이트에 들어간다면 → 그 사이트가 서버로 요청 보내면 브라우저가 자동으로 쿠키 포함해서 전송 → 서버는 정상 요청으로 착각
- 해결 방법 => SameSite, CSRF 토큰
- CSRF (Cross-Site Request Forgery)
10. 세션의 동작 원리를 설명해주세요. 서버는 "이 요청이 아까 그 사용자의 요청"이라는 걸 어떻게 알 수 있나요?
- 세션은 서버가 사용자별 상태 정보를 저장하는 방식입니다.
사용자가 로그인하면 서버는 랜덤한 세션 ID를 생성하고, 해당 세션 ID의 사용자 정보와 로그인 상태를 서버의 세션 저장소에 저장합니다.
이후 세션 ID를 쿠키에 담아 브라우저에 전달하고,
브라우저는 매 요청 시 이 세션 ID를 자동으로 전송합니다.
서버는 전달받은 세션 ID를 통해 세션 저장소를 조회하여 동일 사용자인지 판단합니다.
11. 세션을 사용할 때 서버가 여러 대(다중 서버/로드밸런싱 환경)라면 어떤 문제가 생기나요? 해결 방법은?
문제점
- 서버가 여러 대 일 시 서버A에 로그인 요청을 하고 다음 요청이 서버B로 간다면 해당 서버엔 세션 정보가 없으므로 로그인 상태를 유지할 수 없는 문제가 생깁니다.
- 기본적으로 세션은 서버 메모리에 저장되고 서버끼린 세션을 공유하지 않음
해결 방법
- Sticky Session(세션 고정)
- 한 사용자의 요청 항상 같은 서버로 보내게 로드밸런서가 붙잡아두는 방식
- 장점
- 구현이 쉽고 기존 코드 변경이 적다.
- "지금 당장 세션이 깨지는 문제"는 빠르게 해결됨
- 단점
- 특정 서버가 죽으면 사용자의 세션도 같이 날아감
- 특정 서버에 사용자가 몰리면 과부하가 발생할 수 있다.
- Sticky Session(세션 고정)
- 공용 세션 저장소 사용
- 모든 서버가 같이 보는 공용 저장소에 저장하는 방식
- 장점
- 어떤 서버로 요청이 가도 로그인 유지됨 (로드밸런싱 자유)
- 서버 한 대 죽어도(웹서버) 세션 자체는 남아있을 수 있음
- 수평 확장(서버 늘리기)이 깔끔함
- 단점
- Redis가 느려지거나 죽으면 인증이 전체적으로 영향 받음
→ 그래서 Redis를 고가용성(복제/클러스터/Sentinel) 로 구성함 - 네트워크 왕복(서버↔Redis) 비용이 생김
→ 그래도 대부분 서비스에서 충분히 감당 가능 - 세션 TTL(만료), 동시 로그인 정책 같은 운영 설계 필요
- Redis가 느려지거나 죽으면 인증이 전체적으로 영향 받음
- 공용 세션 저장소 사용
- Stateless 인증 (토큰/JWT 방식)
- 아예 서버에 세션을 저장하지 않는 방식.
로그인 성공 시 서버가 토큰(JWT 같은 것) 을 발급하고,
클라이언트가 매 요청마다 그 토큰을 보내면,
서버는 토큰이 진짜인지 검증해서 로그인 처리. - 이 방식이 다중 서버에 강한 이유
- 서버가 “기억”을 안 함.
그냥 토큰만 검증하면 끝.
그래서 서버 A/B/C 어디로 가든 상관 없음.
- 서버가 “기억”을 안 함.
- 장점
- 세션 저장소가 필요없어 확장에 매우 유리함
- 서버가 가벼워짐
- 분산 구조에 편함
- 단점
- 로그아웃/강제 만료가 어려움
세션은 서버에서 지우면 끝인데,
JWT는 이미 클라이언트가 들고 있으면 만료 전까지 유효해지기 쉬움
해결: 짧은 만료 + refresh 토큰, 토큰 버전, 블랙리스트 등 설계 필요 - 토큰 탈취되면 위험 (특히 XSS)
- 토큰이 커질 수 있음(요청마다 전송하니 비용 증가)
- 로그아웃/강제 만료가 어려움
- 아예 서버에 세션을 저장하지 않는 방식.
- Stateless 인증 (토큰/JWT 방식)
12. 메모리란 무엇인가요?
- 프로그램이 실행되는 동안 데이터를 임시적/영구적으로 보관하는 공간
- 프로세스의 실행 속도와 서버의 처리 성능에 직접적인 영향을 미칩니다.
- RAM(Random Access Memory)
- 단기 기억 장치로 컴퓨터가 작업중인 데이터를 임시로 보관하는 장소 입니다.
- CPU가 데이터를 직접 읽고 쓸 수 있어 하드디스크(HDD/SSD)보다 훨씬 처리 속도가 빠릅니다.
- 전원이 차단되면 저장된 데이터가 모두 지워집니다.(휘발성)
- 메모리 용량이 클수록 여러 프로그램을 동시에 실행하는 멀티태스킹이 원활해집니다.
| RAM | SSD |
|---|---|
| 실행용 | 저장용 |
| 빠르게 읽고 쓰는 게 목적 | 오래 보관하는 게 목적 |
| 휘발성 | 비휘발성 |
- RAM은 전자 신호를 바로 읽고 쓰고 CPU와 바로 연결되기 때문에 빠르고, SSD는 컨르롤러를 거치고 장기 저장용이라 구조적으로 더 느리다.
13. 세션 기반 인증과 토큰(JWT) 기반 인증의 차이를 설명해주세요. 각각의 장단점은?
차이점
- 세션 기반 인증은 서버가 상태(로그인 정보)를 메모리/DB에 저장하고 세션 ID를 쿠키로 관리하는 방식이며,
토큰(JWT) 기반은 서버가 상태를 저장하지 않고(Stateless) 클라이언트가 정보를 포함한 토큰을 저장/제출하는 방식입니다.
- 세션 기반 인증은 서버가 상태(로그인 정보)를 메모리/DB에 저장하고 세션 ID를 쿠키로 관리하는 방식이며,
세션 기반 인증 (Session-based) vs 토큰 기반 인증 (JWT)
- 저장 위치: 세션은 서버, 토큰(JWT)은 클라이언트(쿠키/localStorage)에 저장됩니다.
- 상태 관리: 세션은 Stateful(서버가 기억함), JWT는 Stateless(서버가 기억하지 않고 토큰 자체로 인증)입니다.
- 검증 방식: 세션은 서버에서 DB 조회를 통해, JWT는 서명(Signature) 검증을 통해 인증합니다.
- 세션 기반 인증 (Session-based)
장점
- 보안성: 로그인 상태를 서버에서 관리하므로 즉시 세션을 강제 종료(로그 - 아웃)할 수 있습니다.
- 데이터 크기: 클라이언트에 세션 ID만 전달하므로 네트워크 트래픽이 적습니다.
단점:
- 서버 부하: 사용자 수가 많아지면 서버 메모리/DB에 부하가 증가합니다.
- 확장성: 서버가 여러 대일 경우 세션 저장소를 공유(Redis 등)해야 하는 복잡함이 있습니다.
- 토큰 기반 인증 (JWT - JSON Web Token)
장점
- 확장성(Stateless): 서버가 상태를 저장하지 않아 서버 증설(Scale-out)이 매우 용이합니다.
- 독립성: 토큰 자체에 사용자 정보를 포함하여 DB 조회를 줄입니다.
- 멀티 플랫폼: 웹, 앱 등 다양한 환경에서 쿠키 제한 없이 토큰 사용이 용이합니다.
- 단점
- 보안성: 토큰이 탈취되면 만료 전까지 강제 만료가 어렵습니다.
- 토큰 크기: 정보가 많을수록 토큰이 커져 네트워크 트래픽에 영향을 줄 수 있습니다.
- 구현 복잡도: 토큰 갱신(Refresh Token) 등 관리 시스템이 필요합니다.
- 요약하자면, 적은 인원의 서비스나 보안이 최우선이라면 세션이 유리하고, 서버 확장성이 중요한 대규모 서비스나 분산 시스템 환경이라면 JWT가 더 적합합니다.
14. 데이터베이스를 사용하는 이유는 무엇인가요?
데이터베이스(DB)를 사용하는 이유는 간단히 말해 '데이터를 체계적으로 관리하고, 필요할 때 빠르고 정확하게 꺼내 쓰기 위해서'입니다.
단순히 메모장이나 엑셀 파일에 기록하는 것과 비교했을 때, 데이터베이스는 대규모 데이터를 다루는 데 있어 다음과 같은 핵심적인 강점을 가집니다.
- 데이터의 중복 방지 및 무결성 유지
- 파일 시스템에서는 같은 정보가 여러 파일에 흩어져 있어 데이터가 서로 충실하지 않은 경우가 발생하기 쉽습니다. 하지만 DB는 데이터를 통합 관리하여 중복을 최소화하고, 데이터의 정확성과 일관성(무결성)을 유지합니다.
- 데이터의 중복 방지 및 무결성 유지
- 효율적인 대량 데이터 처리
- 수백만 건의 데이터 중에서 특정 정보를 찾으려 할 때, 엑셀은 멈추거나 느려질 수 있습니다. 데이터베이스는 '인덱스(Index)'라는 색인 기능을 통해 방대한 데이터 속에서도 원하는 정보를 초 단위로 검색할 수 있게 해줍니다.
- 효율적인 대량 데이터 처리
- 다중 사용자 접속 및 공유 (동시성 제어)
- 여러 사람이 동시에 같은 데이터를 수정하려고 하면 데이터가 꼬일 수 있습니다. 데이터베이스는 '동시성 제어' 기능을 통해 여러 사용자가 동시에 안전하게 데이터에 접근할 수 있도록 관리합니다.
- 다중 사용자 접속 및 공유 (동시성 제어)
- 데이터 보안 및 장애 복구
- 보안: 사용자별로 접근 권한을 다르게 설정하여 민감한 정보(개인정보 등)를 보호할 수 있습니다.
- 백업 및 복구: 시스템 오류나 하드웨어 고장이 발생해도 데이터를 이전 상태로 되돌릴 수 있는 강력한 복구 기능을 제공합니다.
- 데이터 보안 및 장애 복구
- 데이터의 독립성
- 데이터베이스를 사용하면 응용 프로그램과 데이터가 서로 분리됩니다. 즉, 데이터의 구조를 조금 변경하더라도 프로그램 전체를 뜯어고칠 필요가 없어 유지보수가 매우 편리합니다.
- 데이터의 독립성
15. 커넥션 풀(Connection Pool)이란 무엇이고, 왜 사용하나요? 커넥션 풀이 없다면 어떤 일이 벌어지나요?
커넥션 풀의 정의
- 커넥션 풀이란 데이터베이스와 연결된 커넥션을 미리 여러개 만들어두고 풀 속에 저장해 두고 있다가 필요할 때에 커넥션 풀에서 가져다 쓰고 다시 풀에 반환하는 기법
커넥션 풀 사용 이유
- 간단하게 말하면 DB 연결 할 때 발생하는 비용과 시간을 줄이기 위해서 입니다.
- 성능 향샹 : 커넥션을 미리 만들어 두었기 때문에 사용자가 요청할 때 마다 새로 연결을 맺는 시간을 대폭 단축할 수 있다.
- 자원 관리 : DB 에 연결할 수 있는 최대 커넥션 생성 갯수를 제한하여 DB 서버 과부화 방지 가능
- 효율성 : 커넥션을 한번 쓰고 버리는게 아니라 재사용 하기 때문에 메모리 자원을 아낄 수 있음
커넥션 풀이 없다면 발생하는 일
- 커넥션 풀이 없다면 매번 DB에 새로운 연결을 해야하기 때문에 다음과 같은 일이 발생합니다.
- 응답 속도 저하: 사용자가 버튼을 누를 때마다 "DB 연결 시도" 단계에서 시간이 소요되어 서비스가 답답하게 느껴집니다.
- 서버 다운: 갑자기 사용자가 몰리면 DB 서버는 수천 개의 새로운 연결 요청을 처리하다가 CPU 점유율 100%를 찍고 멈춰버립니다.
- 자원 낭비: 연결을 맺고 끊는 과정에서 발생하는 네트워크 부하와 메모리 소모 때문에 서버 전체의 효율이 떨어집니다.
16. 트랜잭션이란 무엇인가요? ACID 속성을 설명해주세요
트랜잭션의 정의
- 트랜잭션은 여러 작업을 하나의 논리적 단위로 묶어 모두 성공하거나 모두 실패하게 보장하는 기능 입니다.
- 쉽게 말해, 여러 개의 작업을 하나로 묶어 "전부 성공하든지, 아니면 아예 아무것도 안 한 것처럼 되돌리든지"를 보장하는 장치입니다.
- 데이터의 일관성 유지, 장애 발생 시 복구 가능, 동시성 제어의 목적
- 이 트랜잭션이 안전하게 수행되기 위해 반드시 갖춰야 할 4가지 성질이 바로 ACID입니다.
ACID 속성
- 원자성 (Atomicity)
- 트랜잭션 내의 모든 연산은 반드시 모두 성공적으로 반영되거나, 하나라도 실패하면 전체가 취소되어야 합니다.
- 예: 계좌 이체 중 내 돈은 빠져나갔는데 상대방에게 입금되지 않았다면, 내 돈이 빠져나간 작업까지 취소(Rollback)하여 없던 일로 만듭니다.
- 원자성 (Atomicity)
- 일관성 (Consistency)
- 트랜잭션이 완료된 후에도 데이터베이스는 미리 정해진 규칙(제약 조건)을 모두 만족하는 상태여야 합니다.
- 시스템이 가진 고유한 규칙을 위반하는 데이터 저장 시도는 트랜잭션이 거부됩니다.
- 예: "잔액은 0원보다 작을 수 없다"는 규칙이 있다면, 잔액을 마이너스로 만드는 이체 시도는 실패하고 기존 상태를 유지합니다.
- 일관성 (Consistency)
- 격리성 (Isolation)
- 여러 트랜잭션이 동시에 실행될 때, 서로의 중간 과정에 간섭할 수 없습니다.
- 각각의 트랜잭션은 마치 혼자서 실행되는 것처럼 느껴져야 하며, 실행 중인 데이터에 다른 트랜잭션이 접근하지 못하게 막습니다.
- 격리성 (Isolation)
- 지속성 (Durability)
- 성공적으로 완료(Commit)된 트랜잭션의 결과는 시스템에 장애가 발생하더라도 영구적으로 기록되어야 합니다.
- 갑자기 전원이 꺼지더라도 성공한 작업의 데이터는 손실되지 않고 보존됩니다.
- 지속성 (Durability)
17. 서블릿(Servlet)이란 무엇인가요? Spring의 DispatcherServlet은 어떤 역할을 하나요?
서블릿의 정의
- 서블릿은 JSP 표준이 나오기 전에 만들어진 표준으로 자바로 웹 어플리케이션을 개발할 수 있도록 하기 위해 만들어졌습니다.
- 서블릿은 웹 서버 내에서 돌아가는 자바 프로그램입니다.
웹 서버(Apache 등)는 정적인 페이지(이미 저장된 HTML 파일)만 보여줄 수 있는데, 사용자가 로그인하거나 게시판에 글을 쓰는 등의 동적인 작업을 하려면 자바 코드가 필요합니다.
이때 그 실행을 담당하는 것이 서블릿입니다. - 🧩 EASY
- 브라우저 요청을 받아서 자바 코드로 처리하고 응답을 만들어주는 객체
서블릿 특징
- HTTP 요청 처리: 클라이언트가 던진 HTTP 메시지(GET, POST 등)를 자바 객체로 변환해서 읽게 해줍니다.
- 멀티스레딩: 서블릿은 요청이 올 때마다 프로세스를 새로 만드는 게 아니라, 하나의 객체를 공유하면서 스레드(Thread)만 새로 생성합니다. 덕분에 매우 빠르고 효율적입니다.
- 플랫폼 독립성: 자바 기반이라 어떤 운영체제에서도 돌아갑니다.
- HTTP 기반으로 동작하며 상태는 기본적으로 Stateless 합니다.
서블릿 동작 원리
1단계: 서블릿 객체 생성 및 로딩 (Loading & Instantiation)
사용자가 특정 URL(예: /login)을 브라우저에 치고 엔터를 누릅니다.톰캣의 판단: "어? /login 요청이 왔네? 담당 서블릿이 메모리에 있나?" 확인합니다.
동작 : 만약 처음 요청된 거라면, 톰캣이 해당 서블릿 클래스를 찾아서 메모리에 올리고 객체를 딱 하나 생성합니다. (이게 바로 아까 말한 '싱글톤' 방식입니다.)
2단계: init()[초기화] - "첫 출근 오리엔테이션"
객체가 만들어지자마자 톰캣이 init() 메서드를 딱 한 번 호출합니다.내용 : "너는 앞으로 이런 설정을 가지고 일해야 해"라고 알려주는 단계입니다.
DB에 연결하기 위한 설정값(ID/PW)을 읽어오거나,
커넥션 풀을 미리 준비하는 등의 준비 작업을 합니다.특징: 데이터베이스 연결 정보 설정 등 처음에 딱 한 번만 하면 되는 일들을 여기서 처리합니다. 만약 이미 메모리에 떠 있다면 이 단계는 건너뜁니다.
3단계: service()[실행] - "무한 반복 실무"
요청이 들어올 때마다 톰캣이 service() 메서드를 실행합니다. 여기가 핵심입니다!동작: 톰캣은 HTTP 요청 정보를 담은 HttpServletRequest와 응답을 담을 HttpServletResponse 객체를 만들어서 서블릿에게 던져줍니다.
분기: service()는 내부적으로 "이게 GET이야, POST야?"를 확인한 뒤, 우리가 흔히 아는 doGet()이나 doPost()를 호출합니다.
응답 객체가 제공하는 메서드를 사용해 응답 객체 내부의 필드(데이터 저장 공간)을 채운다.핵심: 손님이 1,000명이면 service()는 1,000번 호출됩니다. 하지만 요리사(객체)는 아까 뽑은 그 사람 그대로입니다. (이게 효율적인 이유입니다.)
4단계: destroy()[소멸] - "퇴사 및 정리"
서버(톰캣)가 꺼질 때 실행됩니다. 또는 코드 변경 시내용: "그동안 수고했어. 열어뒀던 DB 연결 끊고 정리해."
특징: 메모리에서 완전히 사라지기 직전에 딱 한 번 실행되는 마지막 작별 인사입니다.
이렇게 철저하게 단계를 나누어 관리하는 이유는 딱 두 가지입니다.
재사용성: init()을 한 번만 실행하고 객체를 재사용함으로써, 매번 객체를 만드는 시간을 아끼고 빠른 속도를 냅니다.
자동화: 개발자가 "서버 연결해라, 메모리 비워라"라고 코딩할 필요 없이, 비즈니스 로직(데이터 삭제, 수정 등)만 짜면 나머지는 톰캣이 다 알아서 해주기 때문입니다.
서블릿 객체는 "서버가 살아있는 동안 딱 하나만 존재"하며, 하나의 객체가 멀티 쓰레드 요청을 처리합니다.(싱글톤 기법)
Spring의 DispatcherServlet
DispatcherServlet : 모든 HTTP 요청을 가장 먼저 받는 프론트 컨트롤러로, 요청에 대한 적절한 컨트롤러로 위임 하고 처리 결과를 뷰로 연결해줍니다.
이전엔 각 기능마다 서블릿 클래스를 따로 만들어 두었지만 DispatcherServlet은 단 하나의 서블릿만 생성해 요청을 받으면 공통 기능(로그인 여부,권한 인증, 인코딩 설정 등)을 처리합니다.
공통 기능 처리 후 컨트롤러에게 위임합니다.
// 실제 소스코드의 핵심 인스턴스 변수 (FrameworkServlet 상속 계층에 있음)
private WebApplicationContext webApplicationContext;
18. 서블릿의 생명주기(init → service → destroy)를 설명해주세요. 서블릿 객체는 요청마다 새로 만들어지나요?
1단계: 객체 생성 (Single Instance)
- 클라이언트의 첫 요청이 들어오면, 톰캣(서블릿 컨테이너)은 해당 서블릿 클래스를 메모리에 로드하고 인스턴스를 생성합니다. 이 객체는 싱글톤(Singleton)으로 관리되어 서버가 종료될 때까지 메모리에 딱 하나만 존재하며 재사용됩니다.
2단계: 초기화 (init() - 한 번만 실행)
- 객체 생성 직후 톰캣은 init() 메서드를 호출합니다. 이 단계에서 DB 커넥션 풀 준비, 설정 파일 로딩 등 비용이 많이 드는 공통 자원 세팅을 완료합니다. 서버가 살아있는 동안 단 한 번만 실행되므로 매우 효율적입니다.
3단계: 서비스 실행 (service() - 멀티 쓰레드 병렬 처리)
- 요청이 올 때마다 톰캣은 쓰레드 풀(Thread Pool)에서 별도의 쓰레드(일꾼)를 하나씩 할당하여 service() 메서드를 실행합니다.
- 병렬 처리: 요청이 1,000개면 1,000개의 쓰레드가 생성(혹은 배정)되어 동일한 서블릿 객체를 동시에 사용합니다.
- 데이터 격리: 각 쓰레드는 자신만의 Stack(독립된 작업 공간)을 가지므로, 메서드 내부의 지역 변수는 쓰레드 간에 간섭 없이 안전하게 처리됩니다.
- 로직 수행: 톰캣이 생성한 HttpServletRequest(요청 정보)와 HttpServletResponse(응답 그릇)를 인자로 받아, HTTP 메서드(GET/POST)에 따라 비즈니스 로직을 수행하고 응답 데이터를 채웁니다.
- "서블릿 객체는 하나(싱글톤)인데, 일꾼은 여러 명(멀티 쓰레드)이다. 따라서 여러 일꾼이 공유하는 서블릿의 멤버 변수에는 데이터를 저장하면 안 된다(Stateless)."
4단계: 종료 (destroy() - 자원 반납)
- 서버가 종료되거나 서블릿이 컨테이너에서 제거될 때 실행됩니다. init()에서 확보했던 DB 커넥션을 닫거나, 로그를 최종 저장하는 등 사용하던 시스템 자원을 모두 반납하며 안전하게 종료합니다.
19. 서블릿이 싱글톤으로 동작한다면, 동시에 100명이 요청을 보내면 어떻게 처리되나요? 주의해야 할 점은?
- 동시에 100명이 요청을 보내면 요청마다 각 스레드가 할당되어 100개의 스레드가 service() 메서드를 동시에 호출하게 됩니다.
스레드는 자신만의 Stack 영역을 가지고 있어 메서드 안에 정의된 지역변수는 서로 섞이지 않습니다.
요청에 대한 작업을 마친 스레드는 응답 데이터를 채우고 보낸뒤 다시 스레드 풀로 돌아갑니다
이때 주의해야 할 점은 하나의 객체를 여러 스레드가 공유하게 되므로 공유 자원 관리가 생명입니다.
여러 스레드가 동시 접속해도 값이 절대 변하지 않는 설정값(읽기 전용)을 제외하면,
인스턴스 변수에 상태를 저장하거나 요청간의 데이터를 공유하면 안되고,
모든 데이터는 메서드 내부의 지역 변수로 처리해야되는 무상태성(서블릿 객체의 멤버 변수(인스턴스 변수)에 데이터를 저장하지 않는 설계 방식입니다.) 설계를 해야합니다.
20. MVC 패턴에서 Model, View, Controller 각각의 역할은 무엇인가요?
- 맨 처음 서블릿으로 모든 작업을 처리하다보니 HTML을 자바 코드로 직접 작성해야되서 화면 만들기가 너무 힘들었습니다.
- 그래서 JSP를 도입해 HTML에 자바 코드를 삽입할 수 있었고 이때 JSP는 요청 처리, DB 접근, 로직 처리, 화면 생성 등 모든일을 하다보니 코드가 섞이고 유지보수가 어려웠습니다.(모델 1구조)
- 이러한 문제를 해결하기 위해 MVC 패턴을 도입하여 역할을 분리한 구조가 모델2 구조이며, Servlet이 Controller 역할을 하고 JSP는 View를 담당하도록 구조를 개선하였습니다.
MVC 패턴의 각 역할
Model
- 역할 : 데이터 담당(데이터를 만들고,수정,저장 등), 그 데이터를 처리하는 비즈니스 로직 그 자체입니다.
- 특징 : View나 Controller가 어떻게 생겼는지 몰라도 됩니다. 오직 데이터의 생성, 수정, 삭제에만 집중합니다. (예: 로직 처리 클래스, 자바빈)
View
- 역할 : 사용자에게 보여지는 화면 담당
- 특징 : 모델에서 전달된 데이터를 출력하기만 할 뿐 데이터를 수정하거나 계산하지 않습니다. (예: JSP, HTML)
Controller
- 역할 : 사용자에게 입력을 받아 모델과 뷰를 연결하여 흐름을 제어하는 중간 관리자
- 특징 : 사용자의 입력에 따라 "어떤 모델을 불러서 일을 시킬지", 그 결과로 "어떤 뷰를 보여줄지" 결정합니다. (예: 서블릿)
21. Spring MVC에서 하나의 HTTP 요청이 처리되는 흐름을 설명해주세요. (DispatcherServlet → ?)
- 프론트 컨트롤러 패턴 : 모든 요청을 하나의 컨트롤러가 먼저 받아 공통 처리를 수행한 후, 실제 요청을 처리할 컨트롤러로 위임하는 구조입니다.
Spring MVC에서는 DispatcherServlet이 이를 담당합니다.
1. HTTP 요청 수신 (DispatcherServlet)
- 클라이언트가 HTTP 요청을 보내게되면 가장 먼저 DispatcherServlet이 요청을 받습니다. (프론트 컨트롤러 패턴)
2. 핸들러 찾기 (HandlerMapping)
- 핸들러 : 실제 요청을 처리하는 객체 또는 메서드. Spring MVC 에선 보통 컨트롤러의 메서드가 핸들러이다.
- 이 요청을 처리할 수 있는 핸들러(컨트롤러)가 누군지 찾습니다.
- 서버가 켜질때 미리 그려둔 매핑 테이블에서 담당 컨트롤러를 찾아냅니다.
3. 핸들러 실행 (HandlerAdapter)
- 핸들러 어댑터 : 다양한 형태의 컨트롤러(애노테이션, 인터페이스 구현 방식)를 실행할 수 있게 해주는 변환기
- 스프링 MVC에서 DispatcherServlet이 어댑터로부터 최종적으로 전달받는 표준 규격은 바로 ModelAndView 객체입니다.
- 컨트롤러가 메서드에서 String으로 뷰 이름을 반환하든, Map에 데이터를 담아 반환하든, HandlerAdapter는 이 모든 결과물을 ModelAndView라는 자바 객체 타입으로 변환해서 DispatcherServlet에게 던집니다.
4. 컨트롤러 실행 (Controller)
컨트롤러에선 어댑터가 넣어준 DTO나 변수들을 확인하고, Service를 호출합니다. Service는 Repository를 통해 데이터베이스에서 데이터를 가져옵니다.
Service
- 핵심 비즈니스 로직과 트랜잭션
- 로직 수행 : "이미 가입된 회원인가?", "포인트 적립 대상인가?" 같은 비즈니스 규칙을 체크합니다.
- 트랜잭션 관리 : 이게 제일 중요합니다. @Transactional을 걸어서 "DB 작업 하다가 하나라도 실패하면 다 취소(Rollback)해!"라고 명령을 내리는 주체입니다.
- 레포지토리 호출 : 실제 데이터 저장이 필요하면 Repository에게 일을 시킵니다.
레포지토리 (Repository): DB와의 통신 담당
- 서비스는 DB 접근이 필요하면 Repository를 호출해 데이터를 가져옵니다.
- Entity 처리 : 서비스로부터 넘겨받은 데이터를 DB 테이블과 매핑된 Entity 객체에 담아 처리합니다.
- 쿼리 실행 : SELECT, INSERT 같은 SQL을 날리거나, JPA 같은 도구를 써서 DB와 대화합니다.
- 결과 반환 : DB에서 가져온 데이터를 다시 서비스에게 돌려줍니다.
결과 반환 : 서비스가 결과를 돌려주면, 컨트롤러는 이를 ModelAndView 객체에 담아 디스패처서블릿에게 보냅니다.
5. View 결정 (ViewResolver)
ViewResolver는 컨트롤러가 반환한 논리적인 뷰 이름을 실제 파일 경로로 변환해주는 도구이며, 이를 통해 모델 데이터가 결합된 최종 HTML 응답이 만들어집니다.
컨트롤러가 준 논리적인 이름(예: "home")을 실제파일 경로(예: "/WEB-INF/views/home.jsp")로 변환합니다.
만약 이게 없다면, 개발자는 컨트롤러마다 return "/WEB-INF/views/user/login.jsp";라고 전체 경로를 다 적어야 합니다.
나중에 뷰 파일 위치가 바뀌거나 파일 확장자를 .jsp에서 .html로 바꾸고 싶을 때, 모든 컨트롤러 코드를 다 고쳐야 하는 대참사가 일어납니다. 하지만 ViewResolver가 중간에서 변환해주기 때문에 우리는 컨트롤러에서 간단하게 이름만 던지면 되는 겁니다.
6. View 렌더링
View 객체가 모델 데이터를 request 속성에 담아 JSP로 넘기면, JSP가 실행되면서 HTML 태그와 데이터를 결합해 최종 응답을 생성합니다.
View는 Controller에서 Model에 담아준 데이터(user)를 사용해서 동적으로 HTML을 생성합니다. 이렇게 생성된 HTML이 최종 HTTP 응답이 됩니다.
22. Controller에서 비즈니스 로직을 직접 처리하지 않고 Service 계층을 분리하는 이유는 무엇인가요?
- MVC 패턴에서 원래 Model은 데이터 + 비즈니스 로직 전체 영역이다.
하지만 Spring MVC에선 역할이 너무 큰 Model을 Service(비즈니스 로직) + Repository(DB 접근) + 도메인 객체(Entity)로 나누었다. - 서비스 계층은 비즈니스 로직의 중복을 막고, DB 작업의 안정성(트랜잭션)을 보장하며, 역할 분담을 통해 유지보수를 쉽게 만들기 위해 분리합니다.
분리 이유
- 초기에는 Controller에서 비즈니스 로직까지 처리했지만, 관심사 분리와 테스트 용이성, 트랜잭션 관리 등을 위해 Service 계층을 분리하게 되었습니다.
- 코드가 섞이고 중복되서 재사용이 불가능하다.
- 트랜잭션 관리 불가
- 컨트롤러는 데이터의 일관성과 원자성을 책임지는 무거운 비즈니스 로직을 처리하도록 설계되지 않았습니다.
- 트랜잭션 관리 불가
- 테스트 힘듦
- 컨트롤러는 HTTP 환경(서블릿, 요청 데이터 매핑, 프레임워크 기능)에 강하게 결합되어 있어, 순수 비즈니스 로직만 검증하고 싶어도 거대한 가짜 환경을 구축해야 하는 비용이 발생합니다.
- 테스트 힘듦
23. 필터(Filter)란 무엇이고, 어떤 상황에서 사용하나요? 예를 들어 설명해주세요.
- 서블릿 컨테이너(Tomcat 등)가 관리하는 객체로, HTTP 요청이 서블릿(DispatcherServlet)에 전달되기 전과, 응답이 클라이언트에게 가기 직전에 요청/응답 데이터를 가로채서 특정 작업을 수행하는 컴포넌트입니다.
- HTTP 요청과 응답을 변경할 수 있는 재사용 가능한 클래스
사용 상황
- 공통적으로 “모든 요청에 대해 처리해야 하는 작업”이 있을 때 사용한다.
- 공통 보안 및 인증
- 로그인이 안되어 있으면 Controller까지 못가게 막습니다.(리소스 낭비 최소화)
- 토큰 검사, IP 차단
- 공통 보안 및 인증
- 인코딩 변환
- 일일이 하나씩 UTF-8로 설정할 수 없기 때문에 필터로 한번에 설정
- 인코딩 변환
- 자원 접근에 대한 로깅
- 필터는 서블릿 이전 단계에서 실행되므로 모든 요청에 대해 공통 로깅을 하기에 적합하다.
- 로깅은 애플리케이션의 동작 정보를 기록하는 것이며, 문제 분석, 모니터링, 디버깅을 위해 사용된다.
- 자원 접근에 대한 로깅
- 응답 데이터 변환
- HTML 변환, 응답 헤더 변환, 데이터 암호화 등
- 응답 데이터 변환
24. Spring에서 Filter, Interceptor, AOP의 차이를 아는 만큼 설명해주세요. 각각 어떤 상황에 쓰면 좋을까요?
| 단계 | 흐름 요소 | 설명 |
|---|---|---|
| 1 | Client | HTTP 요청 시작 |
| 2 | Filter | 서블릿 레벨에서 요청 가로채기 |
| 3 | DispatcherServlet | Spring MVC의 프론트 컨트롤러 |
| 4 | Interceptor | Spring MVC 레벨에서 Controller 전/후 처리 |
| 5 | Controller | 요청 처리 및 Service 호출 |
| 6 | Service | 비즈니스 로직 수행 |
| 7 | AOP | 메서드 실행 레벨에서 공통 기능 적용 |
| 8 | Repository | 데이터베이스 접근 |
| 구분 | Filter (필터) | Interceptor (인터셉터) | AOP (관심 지향 프로그래밍) |
|---|---|---|---|
| 관리 컨테이너 | 서블릿 컨테이너 (Tomcat 등) | 스프링 컨테이너 | 스프링 컨테이너 |
| 실행 위치 | 웹 앱의 최외곽 (DispatcherServlet 전/후) | 스프링 내부 (Controller 전/후) | 비즈니스 로직 위 (Method 전/후) |
| 대상 (Target) | 모든 HTTP 요청 (전체 URL) | 컨트롤러 (Handler) | 모든 Bean의 메서드 (Service 등) |
| 접근 가능 데이터 | HTTP 요청/응답 헤더 및 바디 | 컨트롤러 객체, ModelAndView | 메서드 파라미터, 리턴값, 예외 |
| 주요 용도 | 보안(XSS), 인코딩, 로깅, IP 차단 | 로그인 체크, 세밀한 권한 제어 | 트랜잭션, 성능 측정, 로깅 |
| 특징 | 스프링과 무관한 전역 처리 | 스프링 빈과 컨트롤러 정보 활용 | 웹 기술과 분리된 순수 로직 처리 |
- 빈(Bean)은 개발자가 직접 new로 생성하지 않고, 스프링 컨테이너가 생성부터 소멸까지 모든 생명주기를 대신 관리해주는 자바 객체입니다.
- 요약: 빈(Bean)은 스프링 컨테이너에 의해 관리되는 자바 객체로, 싱글톤 패턴으로 관리되어 메모리 효율을 높이고 의존성 주입을 통해 객체 간 결합도를 낮추는 역할을 합니다.
- 어노테이션 방식: 클래스 위에 @Component, @Controller, @Service, @Repository 등을 붙입니다. (요즘 대세)
- 설정 방식: @Configuration 클래스 안에서 @Bean 메서드를 작성합니다.
인터셉터
| 특징 | 내용 |
|---|---|
| 적용 범위 | 스프링 컨텍스트 내부 (컨트롤러 중심) |
| 가장 큰 장점 | 컨트롤러 객체 및 메서드 정보(Handler)를 직접 알 수 있음 |
| 데이터 가공 | 컨트롤러가 만든 ModelAndView에 접근하여 데이터 수정 가능 |
| 차단 방식 | preHandle에서 false를 리턴하여 즉시 중단 가능 |
- 인터셉터는 컨트롤러의 실행 전후와 뷰 생성 전후 시점을 정밀하게 제어하며, 특히 컨트롤러와 모델 데이터에 직접 접근할 수 있어 스프링 기반의 권한 제어와 데이터 가공에 최적화되어 있습니다.
- ① 컨트롤러(Handler) 접근 가능
- 필터: 주소창에 /admin이 쳐졌는지만 봅니다.
- 인터셉터: 실행될 메서드에 붙은 어노테이션을 읽습니다.
- 예: 메서드 위에 @VipOnly가 붙어있으면 "아, 이 메서드는 VIP만 실행 가능하구나!"라고 객체 정보를 보고 판단합니다.
- ② 모델(ModelAndView) 데이터 접근 가능 (postHandle)
- 필터: 컨트롤러가 일을 마친 뒤에 무슨 데이터를 만들었는지 전혀 모릅니다.
- 인터셉터: 컨트롤러가 리턴한 ModelAndView 상자를 열어볼 수 있습니다.
- 예: 모든 화면에 로그인한 사용자의 "잔여 포인트"를 보여줘야 한다면, 인터셉터가 모델 상자에 포인트를 슥 집어넣어 줍니다. 필터는 이게 아예 불가능하죠.
- 필터와 인터셉터의 가장 중요한 차이점은 컨트롤러와 모델 데이터에 접근 여부라고 생각합니다.
AOP
핵심 비즈니스 로직과 공통 관심사(로깅, 트랜잭션, 보안 등)를 분리하여, 메서드 실행 시점에 부가 기능을 동적으로 삽입하는 프로그래밍 기법이다.
우리가 코드를 짤 때 두 종류의 로직이 섞입니다.
- 핵심 비즈니스 로직: 회원가입 시 DB에 저장, 돈 송금 (진짜 하고 싶은 일)
- 부가 기능(인프라 로직): 로그 남기기, 실행 시간 측정, 트랜잭션(DB 원자성 관리)
- 모든 서비스 메서드마다 로그 출력, 시간 측정 코드를 복사 붙여넣기 하면 코드가 쓰레기통이 되겠죠? 이걸 AOP라는 포장지로 감싸서 한곳에서 관리하는 겁니다.
동작원리
- AOP는 클래스를 직접 건드리지 않습니다. 대신 '프록시(가짜)'라는 껍데기를 만듭니다.
- 스프링이 MemberService 빈(Bean)을 만들 때, 가짜 객체(Proxy)를 대신 앞에 세웁니다.
- 컨트롤러가 service.join()을 호출하면, 사실은 가짜 객체의 메서드가 호출됩니다.
- 가짜 객체가 로그를 먼저 남기고(Before), 실제 진짜 객체의 로직을 실행(Proceed)한 뒤, 다시 시간을 기록(After)합니다.
25. 필터 체인(Filter Chain)이란 무엇인가요? 여러 필터가 있을 때 실행 순서는 어떻게 결정되나요?
- 필터 체인은 여러 개의 필터가 순차적으로 연결되어 요청과 응답을 처리하는 구조입니다.
- 실행 순서
- web.xml 파일에 관련 정보를 추가
- 등록된 순서대로 실행
- @WebFilter 애노테이션 사용
- 클래스 이름의 알파벳 순서대로 실행
- @Oder 애노테이션 사용
- 클래스 위에 숫자를 지정합니다. 숫자가 낮을수록 우선순위가 높습니다.
- @Oder(1) : 첫번째
- @Oder(2) : 두번째
- web.xml 파일에 관련 정보를 추가
사용 목적
- 필터 체인은 단일 필터로 해결하기 어려운 복잡한 단계별 검사가 필요할 때 씁니다.
- 그리고 필터를 여러개 등록하다보면 서블릿 컨테이너가 자동으로 필터 체인을 구성한다.
- 보통 아래와 같은 순서로 필터를 체이닝(Chaining)해서 사용합니다.
- 로깅 필터 (Logging): "어떤 놈이 들어왔나?" (모든 요청의 로그를 남김)
- 인코딩 필터 (Encoding): "한국말로 대화하자." (UTF-8 강제 세팅)
- 보안/인증 필터 (Security): "너 우리 집 식구 맞아? (로그인 체크)"
- 권한 필터 (Authorization): "식구는 맞는데, 관리자 방에 들어갈 급이 돼?"
언제 사용?
- 기능이 서로 다른 책임을 가질 때(역할 분리)
- 순서가 중요한 경우
- 보안 단계가 여러 개인 경우
- 재사용성을 고려할 때
- 필터 체인은 로깅, 보안, 인코딩 등 서로 다른 목적의 공통 기능들을 단계별로 수행하며, 특정 단계에서 부적절한 요청을 효율적으로 차단하기 위해 사용합니다.
📕 각 CHAPTER 별 정리
CHAPTER 01 : 웹 프로그래밍 기초
JSP(Java Server Pages)
- JSP는 동적 웹 페이지를 작성하기 위해 사용되는 자바의 표준 기술로, 실행 시 Servlet으로 변환되어 HTML 응답을 생성한다.
- 웹 브라우저에 응답하기 전에 서버에서 실행돼서 HTML을 만들어주는 프로그램
Servelt
- HTTP 요청을 처리하기 위해 톰캣에서 실행되는 자바 클래스
- 요청 처리 : 사용자의 입력을 받아 로직을 처리하고 그 결과를 응답으로 만드는 전 과정
- 클라이언트 요청 수신, 비즈니스 로직 처리, 응답 생성
- servelt 은 혼자 실행되지 못해, 톰캣 같은 WAS가 필요
JDK(Java Development Kit)
- JDK는 자바 코드를 컴파일하고 실행하기 위한 개발 도구이며,
톰캣과 같은 자바 기반 웹 애플리케이션 서버가 동작하는 데 필요한 실행 환경을 제공한다.
- JDK는 자바 코드를 컴파일하고 실행하기 위한 개발 도구이며,
톰캣(WAS)
- 톰캣은 자바 웹 애플리케이션(JSP/Servlet)을 실행하는 웹 애플리케이션 서버(WAS) 중 하나이다.
- WAS는 클라이언트의 요청이 오면, 알맞은 프로그램을 실행(JSP)해서 그 결과를 응답으로 돌려준다.
🧩 EASY
- 실질적인 자바 로직은 서블릿에 작성되고,
JSP는 웹 브라우저에 보여질 화면을 생성하는 역할을 한다.
JSP 코드는 실행 시 서블릿으로 변환되며, 이 서블릿은 톰캣과 같은 웹 애플리케이션 서버에 의해 실행된다.
또한 톰캣은 JDK가 제공하는 JVM 위에서 동작한다.
- 실질적인 자바 로직은 서블릿에 작성되고,
CHAPTER 02 : 웹과 웹 프로그래밍
URL(Uniform Resource Locator)
- 웹 브라우저의 주소줄에 표시되는 것
- 인터넷에서 자원의 위치를 식별하기 위한 주소(집 주소)
웹 브라우저
- 인터넷에서 웹 사이트를 보고 상호작용 할 수 있게 해주는 응용 프로그램
- 인터넷 창(크롬,사파리,파이어폭스,엣지)
웹 페이지
- 웹 브라우저에 출력된 내용
웹 사이트
- 홈페이지라고 부르는 웹 사이트는 웹 페이지의 묶음
URL 구성 요소

| 구성 요소 | 설명 |
|---|---|
| 프로토콜 | 웹 브라우저가 서버와 내용을 주고받을 때 사용하는 규칙의 이름이다. 웹 페이지의 주소를 표현할 때는 주로 http 또는 https를 사용한다. |
| 서버 이름 | 웹 페이지를 요청할 서버의 이름을 지정한다. 서버 이름은 javacan.tistory.com과 같은 도메인 이름이나 180.70.134.239와 같은 IP 주소를 사용할 수 있다. |
| 경로 | 웹 페이지의 상세 주소에 해당한다. 즉, 웹 페이지마다 서로 다른 경로를 가진다. |
| 쿼리 문자열 | 추가로 서버에 전달하는 데이터에 해당한다. 같은 경로라도 입력 값에 따라 다른 결과를 보여줘야 할 때 사용한다. 예를 들어 검색 결과 페이지는 쿼리 문자열을 이용해 검색어를 전달한다. |
- HTML(Hyper Text Markup Langauge)
- 웹 브라우저가 해석해서 화면을 그리기 위한 문서 형식(언어)
- HTML을 이용해서 작성했다고 해서 HTML 문서라고도 부른다.
책에서 주로 사용되는 HTML 태그
<html>,<head>,<title>,<body><a><form>,<input><strong>,<b>,<p>,<br><table>,<tr>,<td>
렌더링
- HTML 같은 문서를 바탕으로 웹 브라우저가 실제 화면을 만들어내는 과정
HTTP(Hyper Text Transfer Protocol)
- HTTP는 웹 브라우저와 웹 서버가 HTML, 문자, 이미지, 동영상 같은 다양한 데이터를 주고받을 때 사용하는 통신 규칙이다.
- 크게 두 가지 관점에서 규칙을 정의한다.(요청 규칙, 응답 규칙)
DNS(Domain Name Server)
- 도메인 이름을 IP 주소로 변환해주는 시스템(서버들)
- 웹 브라우저와 웹 서버는 IP 주소를 이용해서 연결하기 때문
포트(Port)
- 한 컴퓨터 안에서 어떤 프로그램과 통신할지를 구분하기 위한 번호다.
- IP 주소만으로는 컴퓨터의 어떤 서버 프로그램을 실행할지 알 수 없다.
http://localhost:8080- 웹 서버가 사용하는 기본 포트 번호는 80
- 톰캣은 기본적으로 8080 포트를 사용
정적 자원 or 정적 페이지
- 요청이 들어와도 내용이 변하지 않고 같은 응답 데이터를 받으므로 동일한 화면을 출력한다.
이렇게 고정된 결과가 출력 된다고 해서 이들 URL에 해당하는 자원을 이렇게 부름(이미지,HTML)
- 요청이 들어와도 내용이 변하지 않고 같은 응답 데이터를 받으므로 동일한 화면을 출력한다.
동적 자원 or 동적 페이지
- 시간이 특정 조건에 따라 응답 데이터가 달라지는 자원.
JSP를 비롯해서 PHP,ASP.net등 많은 웹 관련 기술들이 바로 동적 페이지를 만드는데 사용되는 프로그래밍 기술이다.
- 시간이 특정 조건에 따라 응답 데이터가 달라지는 자원.
웹 프로그래밍
- 웹 프로그래밍이란 웹 브라우저의 요청을 받아 그에 대한 응답 데이터를 생성하는 프로그램을 만드는 것이다.
- JSP 역시 웹 프로그래밍을 할 때 사용되는 기술이다.
CHAPTER 09 : 클라이언트와의 대화 1 - 쿠키
1.1 쿠키란
- 쿠키는 서버가 클라이언트에 저장 시킨 후, 이후 요청마다 다시 전송받아 사용자 상태를 식별하는데 사용하는 데이터
- 웹 브라우저가 보관하는 데이터
- 쿠키는 웹 서버와 웹 브라우저 양쪽에서 생성할 수 있는데, JSP에서 생성하는 쿠키는 웹 서버에서 생성하는 쿠키이다.
- 🧩 EASY
- 쿠키는 서버가 브라우저에 맡겨두는 작은 메모
1.2 쿠키의 구성
- 이름 : 각각의 쿠키를 구별하는 데 사용되는 이름
- 값 : 쿠키의 이름과 관련된 값
- 유효 시간 : 쿠키의 유지 시간
- 도메인 : 쿠키를 전송할 도메인
- 경로 : 쿠키를 전송할 요청 경로
1.3 쿠키 생성하기
JSP에서 쿠키를 생성할 때에는 Cookie 클래스를 사용한다.
Cookie cookie = new Cookie("cookieName", "cookieValue"); response.addCookie(cookie);
- 쿠키는 response 객체의 addCookie() 메서드로 응답에 추가한다.
- respone 이란 서버가 클라이언트(브라우저)에게 돌려주는 답장1.4 쿠키 값 읽어오기
웹 브라우저는 요청 헤더에 쿠키를 저장해서 보내며, JSP는 다음 코드를 사용해서 쿠키 값을 읽어올 수 있다.
Cookie[] cookies = request.getCookies();- request.getCookies() 메서드는 Cookie 배열을 리턴한다.
- 이 메서드는 읽어올 쿠키가 존재하지 않으면 null을 리턴한다.
- null 여부를 확인하지 않고 쿠키를 사용하면 NullPointerException이 발생할 수 있으므로, 쿠키를 사용할 때에는 항상 request.getCookies() 메서드가 리턴한 값이 null인지의 여부를 확인해야 한다.
1.5 쿠키 값 변경 및 쿠키 삭제하기
변경
쿠키 값을 변경하려면 같은 이름의 쿠키를 새로 생성해서 응답 데이터로 보내면 된다.
쿠키의 값을 변경한다는 것은 기존에 존재하는 쿠키의 값을 변경한다는 것이다.
Cookie cookie = new Cookie("name", URLEncoder.encode("새로운값", "utf-8")) response.addCookie(cookie);- 쿠키 값을 변경하려면 쿠키가 존재하는지 먼저 확인해야 한다.
- URL인코딩(URLEncoder.encode()) : 쿠키에 한글을 안전하게 넣기 위한 변환 도구다.
- UTF-8은 한글을 포함한 모든 문자를 안전하게 표현하는 표준 인코딩이다.
삭제
쿠키를 삭제하려면 다음과 같이 Cookie 클래스의 setMaxAge() 메서드를 호출할 때 인자 값으로 0을 주면 된다.
Cookie cookie = new Cookie(name, value); cookie.setMaxAge(0); response.addCookie(cookie);- Cookie 클래스는 쿠키를 삭제하는 기능을 별도로 제공하지 않아, 위 코드 처럼 유효시간을 0으로 지정해준 후 응답 헤더에 추가하면, 웹 브라우저가 관련 쿠키를 삭제하게 된다.
1.6 쿠키의 도메인
기본적으로 쿠키는 그 쿠키를 생성한 서버에만 전송된다.
하지만, 같은 도메인을 사용하는 모든 서버에 쿠키를 보내야 할 때 setDomain() 메서드를 사용한다.
setDomain() 메서드는 생성한 쿠키를 전송할 수 있는 도메인을 지정한다. 다음의 두가지 형식으로 도메인을 지정할 수 있다.
- .somehost.com : 점으로 시작하는 경우 관련 도메인에 모두 쿠리를 전송한다.
예를 들어,mail.somehost.com, www.somehost.com, javacan.somehost.com에 모두 쿠키를 전송한다.www.somehost.com: 특정 도메인에 대해서만 쿠키를 전송한다.
- .somehost.com : 점으로 시작하는 경우 관련 도메인에 모두 쿠리를 전송한다.
- 도메인을 지정할 때 주의할 점은 setDomain()의 값으로 현재 서버의 도메인 및 상위 도메인만 전달할 수 있다는 것이다.
🍪 쿠키 Domain 설정 & 생성 가능 여부 정리
| 요청을 받은 도메인 | 설정한 Domain 값 | 쿠키 생성 여부 | 쿠키가 전송되는 범위 | 설명 |
|---|---|---|---|---|
| www.somehost.com | .somehost.com | ✅ | somehost.com www.somehost.com mail.somehost.com |
상위 도메인 설정 → 모든 하위 도메인 공유 |
| mail.somehost.com | .somehost.com | ✅ | somehost.com www.somehost.com mail.somehost.com |
mail에서도 전체 공유 쿠키 발급 가능 |
| mail.somehost.com | mail.somehost.com | ✅ | mail.somehost.com | 자기 자신 전용 쿠키 |
| mail.somehost.com | www.somehost.com | ❌ | – | 다른 하위 도메인 전용 쿠키는 발급 불가 |
| mail.somehost.com | (Domain 미설정) | ✅ | mail.somehost.com | Host-only 쿠키 (기본값) |
| www.somehost.com | (Domain 미설정) | ✅ | www.somehost.com | 가장 안전한 기본 쿠키 |
1.7 쿠키의 경로
도메인이 쿠키를 공유할 도메인 범위를 지정한다면, 경로는 쿠키를 공유할 기준 경로를 지정한다.
쿠키의 경로를 지정할 때에느 Cookie 클래스의 setPath() 메서드를 사용한다.
http://localhost:8080/chap09/path2/viewCookies.jsp - 이 URL에서 경로는 서버 주소 이후 부분인 /chap09/path2/viewCookies.jsp - 쿠키에서 사용하는 경로는 디렉터리 수준의 경로를 사용한다. 에를 들어 "/" 나 "/chap09" 또는 "/chap09/path2" 등
- setPath() 메서드를 사용하여 쿠키의 경로를 지정하면, 웹 브라우저는 지정한 경로 또는 하위 경로에 대해서만 쿠키를 전송한다.
1.8 쿠키의 유효시간
- 쿠키의 유효시간을 지정하지 않으면 웹 브라우저를 종료할 때 쿠키를 함께 삭제한다.
- 웹 브라우저 종료 후 다시 웹 브라우저를 실행하면 삭제한 쿠키는 서버에 전송되지 않는다.
- 쿠키의 유효시간을 정해 놓으면 그 유효시간 동안 쿠키가 존재하며, 웹 브라우저를 종료해도 유효시간이 지나지 않았으면 쿠키를 삭제하지 않는다.
- 유효 시간을 지정하려면 setMaxAge() 메서드를 사용한다.
setMaxAge()는 초 단위로 유효 시간을 지정한다.
1.9 쿠키를 사용한 로그인 상태 유지, 로그아웃 처리
- 로그인 상태를 확인할 때 가장 많이 사용하는 방법이 바로 쿠키를 이용하는 것이다.
- 1.로그인에 성공하면 특정 이름을 갖는 쿠키를 생성한다.
- 2.해당 쿠키가 존재하면 로그인한 상태라고 판단한다.
- 3.로그아웃하면 해당 쿠키를 삭제한다.
- 로그아웃을 처리하려면 쿠키를 삭제하면 된다.
- 쿠키의 유효시간을 0으로 처리
CHAPTER 10 : 클라이언트와의 대화 2 - 세션
1.1 세션
세션은 서버가 사용자별로 상태 정보를 저장하고 관리하기 위한 공간
세션은 웹 컨테이너(서버 안에 있는 "웹 프로그램 실행 담당자")에 정보를 보관 할 때 사용한다.
웹 컨테이너는 기본적으로 한 웹 브라우저마다 한 세션을 생성한다.
즉, 같은 JSP 페이지라도 웹 브라우저에 따라 서로 다른 세션을 사용한다.쿠키가 클라이언트 측의 데이터 보관소라면 세션은 서버측의 데이터 보관소인 것이다.
세션의 목적은 "서버가 사용자를 기억하기 위한 수단"으로 사용되며,
- 로그인 상태유지
- 사용자 식별
- 장바구니 정보
- 권한 / 인증 정보
- 요청이 끊겨도 같은 사용자임을 서버가 기억하기 위해 사용한다.
세션과 쿠키의 차이점
| 구분 | 쿠키(Cookie) | 세션(Session) |
|---|---|---|
| 저장 위치 | 브라우저(클라이언트) | 서버(웹 컨테이너) |
| 누가 관리 | 브라우저 | 서버 |
| 보안 | ❌ 상대적으로 약함 | ⭕ 상대적으로 강함 |
| 저장 내용 | 작은 데이터 (문자열) | 객체, 상태 정보 |
| 생명 주기 | 만료 시간 기준 | 서버가 관리 (타임아웃) |
| 자동 전송 | 요청 시 자동 전송 | 세션 ID를 통해 식별 |
| 서버 부담 | 거의 없음 | 사용자 많으면 부담 |
🧩 EASY
- 쿠키는 클라이언트에 저장되는 데이터이고, 세션은 서버에 저장되는 사용자 상태 정보다.
보안을 위해 실제 사용자 정보는 세션에 두고, 쿠키에는 세션 ID만 저장한다.1.2 세션 생성하기
JSP에서 세션을 생성하려면 다음과 같이 page 디렉티브의 session 속성을 "true" 로 지정하면 된다.
<% page session = "true" %> - 기본값이 true이므로 session 속성값을 false로 지정하지만 않으면 세션이 생성된다.
1.3 session 기본 객체
- 세션을 사용한다는 것은 session 기본 객체를 사용한다는 것을 말한다.
- seesion 기본 객체는 request 기본 객체와 마찬가지로 속성을 제공하므로
setAttribute(), getAttribute() 등의 메서드를 사용하여 속성값을 저장하거나 읽어올 수 있다. - 각 세션을 구분하기 위해 세션마다 고유 ID를 할당하는데 그 아이디를 세션 ID라고 한다.
- 웹 서버는 웹 브라우저에 세션 ID를 전송하고, 웹 브라우저는 웹 서버에 연결할 때마다 매번 세션 ID를 보내서 웹 서버가 어떤 세션을 사용할지 판단할 수 있게 한다.
- 세션 ID를 클라이언트와 서버 사이에서 전달·공유하기 위해 쿠키를 사용한다.
1.4 기본 객체의 속성 사용
- 한 번 생성된 세션은 지정한 유효 시간 동안 유지되고, 따라서 웹 어플리케이션을 실행하는 동안 지속적으로 사용해야 하는 데이터의 저장소로 세션이 적당하다.
- session 기본 객체는 request 기본 객체와 달리 웹 브라우저의 여러 요청을 처리하는 JSP 페이지 사이에서 공유된다.
따라서, 로그인한 회원 정보 등 웹 브라우저와 일대일로 관련된 값을 저장할 때에는 쿠기 대신 세션을 사용할 수 있다. - 속성에 값을 저장하려면 setAttribute() 메서드
- 속성값을 읽으려면 getAttribute() 메서드
1.5 세션 종료
- 세션을 유지할 필요가 없으면 session.invalidate() 메서드를 사용해서 세션을 종료한다.
- 세션을 종료하면 사용 중인 session 기본 객체를 삭제하고 저장했던 속성 목록도 함께 삭제한다.
1.6 세션 유효 시간
session 기본 객체를 사용할 때마다 세션의 최근 접근 시간은 갱신된다.
session.getLastAccessedTime() - 여기서 getLastAceesedTime() 메서드는 최근에 session 기본 객체에 접근한 시간을 나타낸다.세션을 사용하도록 설정된 JSP 페이지에 접근할 때마다 세션의 최근 접근 시간을 변경한다
세션은 마지막 접근 이후 일정 시간 이내에 다시 세션에 접근하지 않는 경우 자동으로 종료하는 기능을 갖고 있다.
그래서 서버에 데이터가 쌓이지 않도록 유효시간을 두고 삭제해야함세션 유효 시간은 두 가지 방법이 있다.
- 첫째, WEB-INF\web.xml 파일에 다음과 같이
<session-config>태그를 사용하여 세션 유효 시간을 지정하는 방법이다. - 둘째, session 기본 객체가 제공하는 setMaxInactiveInterval() 메서드를 사용하는 것이다.
session.setMaxInactiveInterval(60 * 60); - 유효 시간이 없는 상태에서 session.invalidate() 메서드를 실행하지 않으면, 세션 객체가 계속 메모리에 남게 되어 메모리 부족 현상이 발생하게 된다.
- 메모리 부족 현상을 방지하려면 반드시 세션 타임아웃 시간을 지정 해야한다.
- 첫째, WEB-INF\web.xml 파일에 다음과 같이
1.7 request.getSession()을 이용한 세션 생성
HttpSession을 생성하는 또 다른 방법은 request 기본 객체의 getSession() 메서드를 사용하는 것이다.
page 디렉티브의 session 속성값은 false로 지정한다.
session이 생성된 경우에만 session 객체를 구하고 싶다면, getSession() 메서드에 false 인자로 전달하면 된다.
세션이 존재하는 경우에만 세션 객체를 리턴하고 존재하지 않으면 null을 리턴🧩 EASY
- true = 없으면 만들어도 OK
false = 없으면 쓰지 말자
- true = 없으면 만들어도 OK
1.8 세션을 사용한 로그인 상태 유지
- 세션을 사용해서 로그인을 처리하는 방식은 쿠키를 사용한 방식과 비슷하다.
- 로그인에 성공하면 session 기본 객체의 특정 속성에 데이터를 기록한다.
- 이후로 session 기본 객체의 특정 속성이 존재하면 로그인한 것으로 간주한다.
- 로그아웃할 경우 session.invalidate() 메서드를 호출하여 세션을 종료한다.
CHAPTER 14 : 데이터베이스 프로그래밍 기초
1.1 데이터베이스와 DBMS(DatabaseManagementSystem)
- 데이터베이스란 여러 사용자가 공용으로 사용할 수 있도록 데이터를 체계적으로 저장하고 관리하는 집합체이다.
- 목적은 데이터를 저장했다가 필요할 때에 사용하는 것
- DBMS
- 데이터베이스를 관리하는 시스템으로 오라클,MySQL,MSSQL 서버 등이 있다.
- 데이터의 추가/조회/변경/삭제
- 데이터의 무결성 유지
- 트랜잭션 관리
- 데이터의 백업 및 복원
- 데이터 보안
- 웹 어플리케이션을 구축할 때 주로 사용하는 데이터베이스는 관계형 데이터베이스(RDBMS)이다.
1.2 테이블과 레코드
- 테이블
- RDBMS에서 데이터를 저장하는 장소
- 테이블은 데이터의 길이는 최대 몇 글자인지 등의 정보를 가지고 있는데, 이처럼 테이블의 구조와 관련된 정보를 테이블 '스키마'라고 부른다.
- 테이블의 구조는 각각의 정보를 저장하는 칼럼,칼럼 타입,각 칼럼 길이로 구성된다.
- 테이블에 저장되는 값의 길이에도 제약이 있다
- 🧩 EASY
스키마는 틀이고, 테이블은 그 틀로 만들어진 데이터 저장 공간이다.
스키마는 “값이 아니라, 값이 따라야 할 규칙”이다.
- 레코드
- 테이블에서 하나의 행(row)을 이루는 데이터 묶음이다.
- 하나의 테이블은 여러 개의 레코드로 구성되고 각 레코드는 테이블의 스키마에 정의된 칼럼에 해당하는 값을 갖는다.
- 이 레코드, 칼럼 그리고 테이블을 사용해서 데이터를 저장하고 조회하는 작업을 수행하는 것이 바로 데이터베이스 프로그래밍이다.
1.3 주요키(Primary Key)와 인덱스(Index)
테이블에 저장한 레코드를 사용하려면 각 레코드를 구별하는 방법이 필요하다.
주요키(Primary Key)
레코드를 미리 특정 값을 이용해서 정렬해 놓아 좀 더 빠르게 레코드를 찾을 수 있는 방법
하나의 테이블에 저장된 모든 레코드가 서로 다른 값을 갖는 칼럼을 의미한다.
회원 아이디와 같이 서로 다른 값을 가져야 하는 칼럼을 주요키로 사용한다.
인덱스(Index)
- 데이터 베이스도 레코드의 특정 칼럼을 사용해서 레코드를 쉽게 찾을 수 있도록 미리 정리된 표를 만들어 두는데, 이것이 바로 인덱스이다.
- 데이터의 순서를 미리 정렬해서 저장할 때 사용된다.
- 주요키도 인덱스의 일종으로서, 인덱스는 중복된 값에 대한 정렬이 가능하지만 주요키는 중복된 값을 가질 수 없다는 차이가 있다.
- 🧩 EASY
- 주요키는 데이터를 ‘구분하기 위한 규칙’이고, 인덱스는 데이터를 ‘빨리 찾기 위한 도구’다.
- 🧩 EASY
1.4 데이터베이스 프로그래밍의 필수 요소
- DBMS : 데이터베이스를 관리해주는 시스템
- 데이터베이스 : 데이터를 저장할 공간
- DBMS 클라이언트 : 데이터베이스를 사용하는 어플리케이션
2.1 SQL 기초
- SQL은 'Structured Query Language'의 약자로서 데이터베이스로부터 데이터를 조회하고 삭제하는 등의 작업을 수행할 때 사용하는 언어이다.
- '쿼리'는 데이터베이스에 대한 모든 요청을 의미한다.
2.2 주요 SQL 타입
| 분류 | 타입 | 설명 | 예시 |
|---|---|---|---|
| 숫자 | INT | 정수 | 1, 100, -5 |
| 숫자 | BIGINT | 큰 정수 (PK에 자주 사용) | 9223372036854775807 |
| 숫자 | DECIMAL(p,s) | 정확한 소수 (금액) | 123.45 |
| 숫자 | FLOAT / DOUBLE | 부동소수점 (근사값) | 3.14 |
| 문자 | CHAR(n) | 고정 길이 문자열 | 'A', 'ABC' |
| 문자 | VARCHAR(n) | 가변 길이 문자열 | '김동욱' |
| 문자 | TEXT | 긴 문자열 | 게시글 내용 |
| 날짜 | DATE | 날짜 | 2026-02-09 |
| 날짜 | TIME | 시간 | 14:30:00 |
| 날짜 | DATETIME | 날짜 + 시간 | 2026-02-09 14:30:00 |
| 날짜 | TIMESTAMP | 날짜 + 시간 (시스템 기준) | 2026-02-09 05:30:00 |
| 논리 | BOOLEAN | 참/거짓 | true / false |
| 기타 | BLOB | 이진 데이터 | 이미지, 파일 |
2.3 테이블 생성 쿼리
데이터가 실제로 저장되는 공간은 테이블이므로, 데이터베이스 프로그래밍을 하려면 테이블을 생성해야 한다.
create table TABLENAME( COL_NMAE1 COL_TYPE1(LEN1), COL_NMAE2 COL_TYPE2(LEN2), ..., COL_NMAEn COL_TYPEn(LENn), ) - TABLENAME : 테이블을 식별할 때 사용하는 이름 - COL_NAME : 각 칼럼의 이름 - COL_TYPE : 각 칼럼에 저장될 값의 타입 - LEN : 저장될 값의 최대 길이
주요키 칼럼을 표시할 때에는 칼럼 타입 뒤에 'PRIMARY KEY' 라는 문장을 추가하며, 필수 값에 대해서는 'NOT NULL'을 추가한다.
create table MEMBER( MEMBERID VARCHAR(10) NOT NULL PRIMARY KEY, PASSWORD VARCHAR(10) NOT NULL, NAME VARCHAR(20) NOT NULL, EMAIL VARCHAR(80) ) - PK → DB가 행을 구분하기 위한 필수 조건 - NOT NULL → 비즈니스적으로 반드시 있어야 하는 값 - 필수 요소란, 이 값이 없으면 도메인 개념이 성립하지 않는 속성이다.
2.4 데이터 삽입 쿼리
테이블에 데이터를 추가할 때는 INSERT 쿼리를 사용한다.
insert into (MEMBERID, PASSWORD, NAME) values('madvirus','1234',김동욱); - EMAIL 칼럼의 값을 지정하지 않았는데 이처럼 값을 지정하지 않으면 null값이 들어간다. - SQL에서는 작음따옴표를 사용하여 문자열을 표시한다.
칼럼 목록을 표시하지 않으면 전체 칼럼에 대해 값을 지정해야 한다. 예를 들어, MEMBER 테이블에 레코드를 추가하려면 다음과 같이 칼럼명을 입력하지 않고 모든 칼럼의 값을 순서대로 지정해도 된다.
insert into MEMEBER values('kdong', '0998', '김동욱', 'kimdongd2@naver.com')
2.5 데이터 조회 쿼리 - 조회 및 조건
테이블에 저장된 데이터를 조회할 때에는 SELECT 쿼리를 사용한다.
mysql> select MEMBERID, NAME from MEMBER; +----------+--------+ | MEMBERID | NAME | +----------+--------+ | kdongd | 김동욱 | | madvirus | 김동욱 | +----------+--------+ 2 rows in set (0.00 sec) - MEMBERID 칼럼과 NAME 칼럼의 값을 읽어오는 쿼리를 실행한 결과 화면
만약 전체 칼럼을 모두 읽고 싶으면 전체 칼럼 이름을 적는 대신 다음과 같이 별표('*')를 사용하면 된다
select * from MEMBER;SELECT 쿼리는 기본적으로 모든 레코드의 목록을 읽어온다.
그런데 보통 특정 조건을 충족하는 레코드만 필요한 경우가 많기 때문에 'madvirus'인 회원 정보를 보고 싶으면 WHERE 절을 사용한다.
select * from MEMBER where NAME = '김동욱';위 코드는 NAME 칼럼의 값이 '김동욱'인 레코드의 목록만 읽어온다. AND와 OR를 사용하면 한 개 이상의 조건을 동시에 부여할 수도 있다.
select * from MEMBER where NAME = '김동욱' and EMAIL = 'kimgondgd2@naver.com'; - 위 쿼리는 NAME 칼럼 값이 '김동욱'이고 EMAIL 칼럼 값이 'kimdongd2@naver.com'인 레코드만 검색한다.
같지 않음을 표현할 때에는 '<>' 연산자를 사용한다. 예를 들어, EMAIL 칼럼의 값이 빈 문자열(")이 아닌 레코드를 검색하고 싶다면
select * from MEMBER where EMAIL <> ";칼럼 값이 NULL이거나 NULL이 아닌 레코드를 구하고 싶을 때
select * from MEMBER where EMAIL is NULL; select * from MEMBER where EMAIL is not NULL;부등호 기호로 숫자 범위 사이에 있는 레코드를 읽고 싶을 때
where SALARY >= 1000 and SALARY <= 2000LIKE 조건을 사용해서 특정 문장을 포함하고 있는지 검사할 수 있다. 예를 들어, NAME 칼럼이 '김'으로 시작하는 레코드를 찾고 싶다면
where NMAE like '김%' - '%'는 모든 것을 의미한다. - '%김%'과 같이 조건을 주면 앞뒤로 모든 문장이 오고 중간에 '김'이 포함된 값인지의 여부를 판단하게 된다. - LIKE 검색은 편리하지만 속도는 매우 느리다
2.6 데이터 쿼리 조회 - 정렬
SQL 쿼리에서는 ORDER BY 절을 사용해서 데이터 정렬을 처리한다.
ORDER BY 절은 WHERE 절 뒤에(WHERE 절이 없으면 FROM 절 뒤) 붙으며 다음과 같이 사용된다.
select .. from[테이블 이름] where[조건절] order by[칼럼1] asc, [칼럼2] desc, ...;- asc 는 오름차순, desc 는 내림차순이다.
- 여러 칼럼을 지정하면 앞 칼럼 기준으로 먼저 정렬한다.
2.7 데이터 쿼리 조회 - 집합
집합 관련된 쿼리에는 sum(), max(), count() 등의 함수가 있다.
각각 총합, 최대, 최소, 개수를 구할 때 사용된다.
가장 큰 값, 가장 작은 값 그리고 전체 레코드 칼럼 합을 구할 때
select max(SALARY), min(SALARY), sum(SALARY) from MEMBER;전체 레코드 개수를 구할 때
select count(*) from MEMBER;NAME 칼럼 값이 '김'으로 시작하는 레코드의 개수를 구하고 싶을 때
select count(*) from MEMBER where NAME like '김%';
2.8 데이터 수정 쿼리
데이터를 수정할 때에는 UPDATE 쿼리를 사용한다.
update [테이블이름] set [칼럼1]=[값1],[칼럼2]=[값2], .. where [조건절];WHERE 절을 생략하면 모든 레코드가 수정되므로 주의해야 한다.
2.9 데이터 삭제 쿼리
DELETE 쿼리를 실행해서 레코드 단위로 데이터를 삭제할 수 있다.
delete from [테이블이름] where [조건절]WHERE 절을 생략하면 테이블의 모든 레코드가 삭제된다.
2.10 조인
조인(join)은 두 개 이상의 테이블에서 관련 있는 데이터를 함께 읽어올 때 사용된다.
- 기본 형식 select A. 칼럼1, A. 칼럼2, B. 칼럼3, B. 칼럼4 from [테이블1] as A, [테이블2] as B where a.[칼럼x] = B.[칼럼y]
MEMBER_ETC 테이블에 여러 레코드를 삽입한 후 쿼리 실행
mysql>select * from MEMBER A, MEMBER_ETC B -> where A.MEMBERID = B.MEMBERID; | MEMBERID | PASSWORD | NAME | MEMBERID | EMAIL | BIRTHDAY | |----------|----------|--------|----------|-------------------|------------| | eral3 | 1234 | 김동욱 | eral3 | eral3@test.com | 1997-01-01 | | madvirus | 5678 | 김동욱 | madvirus | null | 1997-02-02 | - 조인을 사용하면 관련된 테이블로부터 필요한 칼럼을 모아서 한꺼번에 읽어올 수 있기 때문에, 여러 테이블에 분산해서 저장된 정보를 읽어올 때 유용하게 사용할 수 있다.
3.1 JDBC
- JDBC는 Java DataBase Connectivity의 약자로서 자바에서 데이터베이스와 관련된 작업을 처리할때 사용하는 API다.